diff --git a/autonomy/brain.py b/autonomy/brain.py index 83a8a921..21db199d 100644 --- a/autonomy/brain.py +++ b/autonomy/brain.py @@ -429,7 +429,6 @@ def _sync_live_exposure(self, outcomes: list[TradeOutcome]) -> None: OutcomeKind.FILLED: "filled", OutcomeKind.CANCELED: "canceled", OutcomeKind.EXPIRED: "expired", - OutcomeKind.REJECTED: "rejected", } for outcome in outcomes: order_id = str(outcome.order_id or "").strip() @@ -437,8 +436,7 @@ def _sync_live_exposure(self, outcomes: list[TradeOutcome]) -> None: continue terminal_state = terminal_states.get(outcome.kind) if outcome.kind is OutcomeKind.PARTIALLY_FILLED or terminal_state: - proposal_id = tracker.client_order_id_for(order_id) - persisted = tracker.record_cumulative_fill( + tracker.record_cumulative_fill( order_id, int(outcome.fill_count), ( @@ -447,58 +445,6 @@ def _sync_live_exposure(self, outcomes: list[TradeOutcome]) -> None: ), terminal_state=terminal_state, ) - capital_adapter = getattr( - self.executor, "capital_envelope_adapter", None - ) - witnessed_state = str( - outcome.detail.get("state") or "" - ).strip().lower() - terminal_witnesses = { - "filled": {"filled", "executed"}, - "canceled": {"canceled", "cancelled"}, - "expired": {"expired"}, - "rejected": {"rejected"}, - } - if ( - persisted - and terminal_state is not None - and witnessed_state - in terminal_witnesses.get(terminal_state, set()) - and proposal_id - and capital_adapter is not None - and outcome.broker_contacted is True - ): - receipt = { - "schema": "dummy.terminal-order-reconciliation.v1", - "terminal_status": terminal_state, - "proposal_id": proposal_id, - "decision_id": outcome.decision_id, - "market_ticker": outcome.market_ticker, - "order_id": order_id, - "fill_count": int(outcome.fill_count), - "fill_price_cents": outcome.fill_price_cents, - "broker_contacted": True, - "outcome_created_at": outcome.created_at, - "detail": dict(outcome.detail), - "local_exposure_projection_persisted": True, - } - try: - capital_adapter.release_from_terminal_reconciliation( - proposal_id=proposal_id, - terminal_status=terminal_state, - reconciliation_receipt=receipt, - ) - except Exception: - # Retaining the capital reservation is the fail-closed - # response to a missing/malformed terminal receipt. - logger.exception( - "DumbMoney terminal reservation release failed", - extra={ - "component": "reconciliation", - "proposal_id": proposal_id, - "order_id": order_id, - }, - ) def _close_position(self, state: RiskState, open_decision: dict[str, Any], result_yes: bool) -> None: diff --git a/autonomy/executor.py b/autonomy/executor.py index 7c2d6c38..e3457b6b 100644 --- a/autonomy/executor.py +++ b/autonomy/executor.py @@ -95,8 +95,6 @@ def __init__( exchange_status_fn: Callable[[], dict[str, Any]] | None = None, now_fn: Callable[[], float] | None = None, execution_policy: ExecutionPolicy | None = None, - capital_envelope_adapter: Any | None = None, - core_submission_authority: Callable[[], bool] | None = None, ) -> None: self.mode = mode # Typed execution policy (Wave-2 A2/F2; Wave-5 taker path). The default @@ -133,11 +131,6 @@ def __init__( # failed, or malformed status blocks the submit # (exchange_status_unavailable_at_submit), as does maintenance/halt. self.exchange_status_fn = exchange_status_fn - # Optional DumbMoney deny-only capital ceiling. This adapter cannot - # replace the session acknowledgement, local risk state, kill switch, - # central firewall, or live-submit authority. - self.capital_envelope_adapter = capital_envelope_adapter - self.core_submission_authority = core_submission_authority self._now_fn = now_fn or (lambda: datetime.now(timezone.utc).timestamp()) # Counter so a refusal is never a silent skip: surfaced on the executor # for the daemon/dashboard, and each refusal is also recorded as a @@ -338,17 +331,11 @@ def _make_firewall(self): from live_firewall.exposure_tracker import get_persistent_exposure_tracker from live_firewall.firewall import LiveBrokerFirewall - if self.capital_envelope_adapter is None: - raise RuntimeError( - "DumbMoney capital adapter is mandatory for LIVE execution" - ) return LiveBrokerFirewall( KalshiClient(), get_persistent_exposure_tracker(), autonomy_risk_state_path=self.risk_state_path, require_autonomy_risk_state=True, - capital_envelope_adapter=self.capital_envelope_adapter, - core_submission_authority=self.core_submission_authority, ) def _risk_state_digest(self) -> str | None: @@ -558,11 +545,6 @@ async def _execute_live_via_firewall( ) -> TradeOutcome: if market is None or market.ticker != decision.market_ticker: return self._blocked(decision, "live_market_context_missing_or_mismatched") - if self.capital_envelope_adapter is None: - return self._blocked( - decision, - "dumbmoney_capital_adapter_required_for_live_execution", - ) try: firewall = self._make_firewall() except Exception as exc: @@ -578,27 +560,6 @@ async def _execute_live_via_firewall( risk_digest = self._risk_state_digest() if risk_digest is None: return self._blocked(decision, "persisted_autonomy_risk_state_unavailable") - capital_binding: dict[str, Any] = {} - if self.capital_envelope_adapter is not None: - from live_firewall.dumbmoney_capital import strategy_binding_hash - - try: - capital_binding = self.capital_envelope_adapter.binding_for( - strategy_hash=strategy_binding_hash( - f"autonomy_strategy_v2:{decision.decision_id}" - ), - passport_hash=strategy_binding_hash( - f"autonomy_forecast:{decision.decision_id}" - ), - authorized_instrument=( - f"event_contract:{decision.market_ticker}" - ), - ) - except Exception as exc: - return self._blocked( - decision, - f"signed_capital_envelope_unavailable:{type(exc).__name__}", - ) client = getattr(firewall, "client", None) get_orderbook = getattr(client, "get_orderbook", None) if not callable(get_orderbook): @@ -636,7 +597,6 @@ async def _execute_live_via_firewall( "risk_state_sha256": risk_digest, "risk_snapshot": dict(decision.risk_snapshot), "expiration_ts": expiration_ts, - **capital_binding, } request = LiveOrderRequest( **request_fields, diff --git a/autonomy/kill_reconciliation.py b/autonomy/kill_reconciliation.py index 13f6503b..4f1115a0 100644 --- a/autonomy/kill_reconciliation.py +++ b/autonomy/kill_reconciliation.py @@ -63,62 +63,28 @@ def queue_kill_reconciliation( *, kill_asserted_at: str, receipt_path: Path | None = DEFAULT_KILL_RECONCILIATION_PATH, - capital_envelope_adapter: Any | None = None, ) -> dict[str, Any]: - """Record that cancel/reconcile remains required; perform no broker I/O. - - A DumbMoney adapter may be supplied to mirror the state into the compact - operational journal. This queue path always records ``cancel_authority`` - false; a capital grant never supplies cancellation authority. - """ - payload: dict[str, Any] = { - "kill_reconciliation_version": KILL_RECONCILIATION_VERSION, - "generated_at": datetime.now(timezone.utc).isoformat(), - "kill_asserted_at": kill_asserted_at, - "status": "PENDING_CANCEL_AND_RECONCILE", - "submission_authority": False, - "cancel_authority": False, - "broker_contacted": False, - "canceled_order_ids": [], - "open_orders_after": None, - "residual_positions": None, - "flat_book_observed": False, - "liquidation_attempted": False, - "operator_action": ( - "run the separately authorized central cancellation and " - "reconciliation procedure" - ), - } - if capital_envelope_adapter is not None: - try: - parsed_kill_at = datetime.fromisoformat( - str(kill_asserted_at).replace("Z", "+00:00") - ) - if parsed_kill_at.tzinfo is None: - raise ValueError("kill_asserted_at must be timezone-aware") - canonical_kill_at = ( - parsed_kill_at.astimezone(timezone.utc) - .isoformat() - .replace("+00:00", "Z") - ) - operational = capital_envelope_adapter.enter_cancel_only( - reason="Dummy kill reconciliation queued", - kill_asserted_at=canonical_kill_at, - cancel_authorized=False, - ) - payload["dumbmoney_operational_event_sha256"] = operational[ - "event_sha256" - ] - payload["dumbmoney_operational_status"] = ( - "CANCEL_AUTHORITY_REQUIRED" - ) - except Exception as exc: - # The KILL queue still persists locally; journal failure can only - # reduce authority and is exposed for operator reconciliation. - payload["dumbmoney_operational_status"] = ( - f"JOURNAL_FAILED:{type(exc).__name__}" - ) - receipt = _stamp(payload) + """Record that cancel/reconcile remains required; perform no broker I/O.""" + receipt = _stamp( + { + "kill_reconciliation_version": KILL_RECONCILIATION_VERSION, + "generated_at": datetime.now(timezone.utc).isoformat(), + "kill_asserted_at": kill_asserted_at, + "status": "PENDING_CANCEL_AND_RECONCILE", + "submission_authority": False, + "cancel_authority": False, + "broker_contacted": False, + "canceled_order_ids": [], + "open_orders_after": None, + "residual_positions": None, + "flat_book_observed": False, + "liquidation_attempted": False, + "operator_action": ( + "run the separately authorized central cancellation and " + "reconciliation procedure" + ), + } + ) _write_atomic(receipt_path, receipt) return receipt diff --git a/autonomy/reconciler.py b/autonomy/reconciler.py index e7136295..ac20e213 100644 --- a/autonomy/reconciler.py +++ b/autonomy/reconciler.py @@ -9,12 +9,12 @@ from datetime import datetime, timezone from decimal import Decimal, InvalidOperation, ROUND_HALF_UP +import os from typing import Any, Callable from autonomy.fees import kalshi_maker_fee_cents, kalshi_taker_fee_cents from autonomy.ledger import AutonomyLedger from autonomy.ontology import MarketView, OutcomeKind, TradeOutcome -from kalshi.strict_json import load_strict_json_response STALE_ORDER_MINUTES = 45 @@ -22,7 +22,6 @@ # "phantom grading coverage % is not emitted anywhere"). Bump only on a # breaking shape change; dashboards read this block off the cycle report. PHANTOM_COVERAGE_VERSION = "phantom-coverage-v1" -_KALSHI_PUBLIC_BASE = "https://external-api.kalshi.com/trade-api/v2" def _series_of(ticker: str) -> str: @@ -65,25 +64,9 @@ def _whole_cents(amount_dollars: Decimal | None) -> int | None: def _public_base() -> str: - """Return the reviewed production endpoint, never an ambient override.""" - return _KALSHI_PUBLIC_BASE - - -def _public_get( - path: str, - *, - params: dict[str, Any] | None = None, - timeout_seconds: float, -) -> Any: - """GET broker truth without inheriting proxy or netrc configuration.""" - import httpx - - with httpx.Client( - base_url=_KALSHI_PUBLIC_BASE, - timeout=max(0.1, float(timeout_seconds)), - trust_env=False, - ) as client: - return client.get(path, params=params) + base = os.environ.get("KALSHI_API_BASE", "https://api.elections.kalshi.com").rstrip("/") + version = os.environ.get("KALSHI_API_VERSION", "trade-api/v2").strip("/") + return f"{base}/{version}" def default_fetch_market_result( @@ -91,36 +74,38 @@ def default_fetch_market_result( *, timeout_seconds: float = 15.0, ) -> dict[str, Any]: - response = _public_get( - f"/markets/{ticker}", - timeout_seconds=timeout_seconds, + import httpx + + response = httpx.get( + f"{_public_base()}/markets/{ticker}", + timeout=max(0.1, float(timeout_seconds)), ) response.raise_for_status() - market = load_strict_json_response(response).get("market", {}) + market = response.json().get("market", {}) return market if isinstance(market, dict) else {} def default_fetch_settled_page(series_ticker: str, min_close_ts: int, cursor: str | None = None) -> dict[str, Any]: """One page of recently settled markets for a series (public GET).""" + import httpx + params: dict[str, Any] = { "series_ticker": series_ticker, "status": "settled", "min_close_ts": min_close_ts, "limit": 200, } if cursor: params["cursor"] = cursor - response = _public_get( - "/markets", - params=params, - timeout_seconds=20, - ) + response = httpx.get(f"{_public_base()}/markets", params=params, timeout=20) response.raise_for_status() - data = load_strict_json_response(response) + data = response.json() return data if isinstance(data, dict) else {} def default_fetch_trades(ticker: str, min_ts: int, max_ts: int) -> list[dict[str, Any]]: """Fetch standard-book public prints for an exact market/time window.""" + import httpx + collected: list[dict[str, Any]] = [] cursor: str | None = None for _page in range(5): @@ -130,13 +115,9 @@ def default_fetch_trades(ticker: str, min_ts: int, max_ts: int) -> list[dict[str } if cursor: params["cursor"] = cursor - response = _public_get( - "/markets/trades", - params=params, - timeout_seconds=20, - ) + response = httpx.get(f"{_public_base()}/markets/trades", params=params, timeout=20) response.raise_for_status() - payload = load_strict_json_response(response) + payload = response.json() rows = payload.get("trades") or [] if isinstance(rows, list): collected.extend(row for row in rows if isinstance(row, dict)) @@ -413,25 +394,11 @@ def reconcile_open_orders(self) -> list[TradeOutcome]: wrapped = status_payload.get("order") status = wrapped if isinstance(wrapped, dict) else status_payload state = str(status.get("status", "")).lower() - raw_filled = status.get("fill_count_fp") - if raw_filled is None or raw_filled == "": - raw_filled = status.get("fill_count") - if raw_filled is None or raw_filled == "": - raw_filled = status.get("filled_count", 0) - filled_decimal = _decimal_or_none(raw_filled) - # Dummy's position, ledger, and capital units are currently whole - # contracts. Never truncate a broker fixed-point fill: 0.50 is - # real exposure, not zero. Until every downstream unit supports - # fixed point, retain the open order/capital reservation and emit - # no terminal fact for any fractional, negative, or malformed - # count. - if ( - filled_decimal is None - or filled_decimal < 0 - or filled_decimal != filled_decimal.to_integral_value() - ): - continue - filled = int(filled_decimal) + try: + filled = int(float(status.get("fill_count_fp") or status.get("fill_count") + or status.get("filled_count") or 0)) + except (TypeError, ValueError): + filled = 0 prior_filled = int(open_decision.get("filled_count") or 0) created = str(status.get("created_time", "")) fill_price, fill_detail = self._broker_fill_evidence( @@ -447,16 +414,6 @@ def reconcile_open_orders(self) -> list[TradeOutcome]: open_decision, OutcomeKind.CANCELED, order_id, filled, {"state": state, **fill_detail}, fill_price, )) - elif state == "expired": - outcomes.append(self._outcome( - open_decision, OutcomeKind.EXPIRED, order_id, filled, - {"state": state, **fill_detail}, fill_price, - )) - elif state == "rejected": - outcomes.append(self._outcome( - open_decision, OutcomeKind.REJECTED, order_id, filled, - {"state": state, **fill_detail}, fill_price, - )) elif filled > prior_filled: outcomes.append(self._outcome( open_decision, OutcomeKind.PARTIALLY_FILLED, order_id, filled, @@ -469,27 +426,7 @@ def reconcile_open_orders(self) -> list[TradeOutcome]: )) elif state == "resting" and self._is_stale(created) and self.cancel_fn is not None: try: - cancel_payload = self.cancel_fn(order_id) - wrapped_cancel = ( - cancel_payload.get("order") - if isinstance(cancel_payload, dict) - else None - ) - cancel_status = ( - wrapped_cancel - if isinstance(wrapped_cancel, dict) - else cancel_payload - ) - confirmed_state = ( - str(cancel_status.get("status") or "").lower() - if isinstance(cancel_status, dict) - else "" - ) - # A cancel request/204 is not a terminal order witness. - # Retain the order until this response or a later status - # read explicitly reports canceled/cancelled. - if confirmed_state not in {"canceled", "cancelled"}: - continue + self.cancel_fn(order_id) role = str(open_decision.get("liquidity_role") or "maker") reason = ( "stale_taker_remainder_auto_cancel" @@ -497,12 +434,7 @@ def reconcile_open_orders(self) -> list[TradeOutcome]: ) outcomes.append(self._outcome( open_decision, OutcomeKind.CANCELED, order_id, filled, - { - "state": confirmed_state, - "reason": reason, - **fill_detail, - }, - fill_price, + {"reason": reason, **fill_detail}, fill_price, )) except Exception: pass diff --git a/configs/dumbmoney/dummy-kalshi-runner.v1.template.json b/configs/dumbmoney/dummy-kalshi-runner.v1.template.json deleted file mode 100644 index 112705e0..00000000 --- a/configs/dumbmoney/dummy-kalshi-runner.v1.template.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "schema": "dummy.dumbmoney-kalshi-runner-config.v1", - "service_name": "DumbMoneyDummyKalshi", - "release_id": "REPLACE_WITH_RELEASE_ID", - "core_endpoint_ref": "endpoint-ref:DumbMoneyCore", - "core_readiness_path": "C:\\ProgramData\\DumbMoney\\readiness\\DumbMoneyCore.json", - "core_cell_token_target": "credential-target:DumbMoney/DummyCellToken", - "kalshi_key_id_target": "credential-target:DumbMoney/KalshiApiKeyId", - "kalshi_private_key_target": "credential-target:DumbMoney/KalshiPrivateKeyPem", - "readiness_signing_key_target": "credential-target:DumbMoney/DummyReadinessEd25519", - "start_mode": "RECONCILIATION_ONLY", - "data_root": "C:\\ProgramData\\DumbMoney\\dummy-kalshi", - "readiness_ref": "readiness-ref:DumbMoneyDummyKalshi", - "readiness_path": "C:\\ProgramData\\DumbMoney\\readiness\\DumbMoneyDummyKalshi.json", - "core_public_keys_base64url": { - "34750f98bd59fcfc946da45aaabe933be154a4b5094e1c4abf42866505f3c97e": "iojj3XQJ8ZX9UtstPLpdcspnCb8dlBIb83SIAbQPb1w" - }, - "operator_public_keys_base64url": { - "6a3803d5f059902a1c6dafbc9ba4729212f7caac08634cc3ae76b27529f03827": "gTl3Dqh9F19Wo1Rmw0x-zMuNipG07jeiXfYPW4_Js5Q" - }, - "promoter_public_keys_base64url": { - "b62e867fa2f33afe62d5d6b1642e1621d543307846b2a57b897e710919b76709": "7UkoxijRwsbq6QM4kFmVYSlZJzpcY_k2NsFGFKyHN9E" - }, - "research_public_keys_base64url": { - "c5b940ed3f65c391965de8295fc5d25f474fa57b48d36eb10ad363b8539c1b79": "ypOsFwUYcHHWe4PH_w7-gQjo7EUwV113JoeTM9vavnw" - }, - "evaluator_public_keys_base64url": { - "72456720412037a6b339f884ce6d91bb4cc163a7dc3e4c58c658e6c2097b92a2": "iodf_x6zhFFXes1a_uQFRWVo3XyJ4JCGOgVXvHr0nxc" - }, - "expected_account_hash": "0000000000000000000000000000000000000000000000000000000000000000", - "kalshi_subaccount_number": 0, - "fund_lock_sha256": "0000000000000000000000000000000000000000000000000000000000000000", - "service_manifest_sha256": "0000000000000000000000000000000000000000000000000000000000000000", - "role_public_keys_sha256": "0000000000000000000000000000000000000000000000000000000000000000", - "core_runner_config_sha256": "0000000000000000000000000000000000000000000000000000000000000000", - "risk_policy_sha256": "0000000000000000000000000000000000000000000000000000000000000000", - "readiness_signer_public_key_sha256": "7599776c3085e3f9da0d13071eb0b4ab50fd2bf64c06dd92c2365af3a328eca3", - "poll_interval_seconds": 5, - "readiness_ttl_seconds": 30, - "broker_truth_max_age_seconds": 30 -} diff --git a/configs/dumbmoney/schemas/dummy-kalshi-runner.v1.schema.json b/configs/dumbmoney/schemas/dummy-kalshi-runner.v1.schema.json deleted file mode 100644 index b9a6d56c..00000000 --- a/configs/dumbmoney/schemas/dummy-kalshi-runner.v1.schema.json +++ /dev/null @@ -1,169 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "urn:dumbmoney:schema:dummy-kalshi-runner:v1", - "title": "DumbMoney Dummy Kalshi Windows runner public config", - "type": "object", - "additionalProperties": false, - "required": [ - "schema", - "service_name", - "release_id", - "core_endpoint_ref", - "core_readiness_path", - "core_cell_token_target", - "kalshi_key_id_target", - "kalshi_private_key_target", - "readiness_signing_key_target", - "start_mode", - "data_root", - "readiness_ref", - "readiness_path", - "core_public_keys_base64url", - "operator_public_keys_base64url", - "promoter_public_keys_base64url", - "research_public_keys_base64url", - "evaluator_public_keys_base64url", - "expected_account_hash", - "kalshi_subaccount_number", - "fund_lock_sha256", - "service_manifest_sha256", - "role_public_keys_sha256", - "core_runner_config_sha256", - "risk_policy_sha256", - "readiness_signer_public_key_sha256", - "poll_interval_seconds", - "readiness_ttl_seconds", - "broker_truth_max_age_seconds" - ], - "properties": { - "schema": { - "const": "dummy.dumbmoney-kalshi-runner-config.v1" - }, - "service_name": { - "const": "DumbMoneyDummyKalshi" - }, - "release_id": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "core_endpoint_ref": { - "const": "endpoint-ref:DumbMoneyCore" - }, - "core_readiness_path": { - "const": "C:\\ProgramData\\DumbMoney\\readiness\\DumbMoneyCore.json" - }, - "core_cell_token_target": { - "const": "credential-target:DumbMoney/DummyCellToken" - }, - "kalshi_key_id_target": { - "const": "credential-target:DumbMoney/KalshiApiKeyId" - }, - "kalshi_private_key_target": { - "const": "credential-target:DumbMoney/KalshiPrivateKeyPem" - }, - "readiness_signing_key_target": { - "const": "credential-target:DumbMoney/DummyReadinessEd25519" - }, - "start_mode": { - "const": "RECONCILIATION_ONLY" - }, - "data_root": { - "const": "C:\\ProgramData\\DumbMoney\\dummy-kalshi" - }, - "readiness_ref": { - "const": "readiness-ref:DumbMoneyDummyKalshi" - }, - "readiness_path": { - "const": "C:\\ProgramData\\DumbMoney\\readiness\\DumbMoneyDummyKalshi.json" - }, - "core_public_keys_base64url": { - "$ref": "#/$defs/key_map" - }, - "operator_public_keys_base64url": { - "$ref": "#/$defs/key_map" - }, - "promoter_public_keys_base64url": { - "$ref": "#/$defs/key_map" - }, - "research_public_keys_base64url": { - "$ref": "#/$defs/key_map" - }, - "evaluator_public_keys_base64url": { - "$ref": "#/$defs/evaluator_key_map" - }, - "expected_account_hash": { - "$ref": "#/$defs/sha256" - }, - "kalshi_subaccount_number": { - "type": "integer", - "minimum": 0, - "maximum": 1000000 - }, - "fund_lock_sha256": { - "$ref": "#/$defs/sha256" - }, - "service_manifest_sha256": { - "$ref": "#/$defs/sha256" - }, - "role_public_keys_sha256": { - "$ref": "#/$defs/sha256" - }, - "core_runner_config_sha256": { - "$ref": "#/$defs/sha256" - }, - "risk_policy_sha256": { - "$ref": "#/$defs/sha256" - }, - "readiness_signer_public_key_sha256": { - "$ref": "#/$defs/sha256" - }, - "poll_interval_seconds": { - "type": "integer", - "minimum": 5, - "maximum": 300 - }, - "readiness_ttl_seconds": { - "type": "integer", - "minimum": 10, - "maximum": 120 - }, - "broker_truth_max_age_seconds": { - "type": "integer", - "minimum": 5, - "maximum": 120 - } - }, - "$defs": { - "sha256": { - "type": "string", - "pattern": "^[0-9a-f]{64}$" - }, - "public_key": { - "type": "string", - "pattern": "^[A-Za-z0-9_-]{43}$" - }, - "key_map": { - "type": "object", - "minProperties": 1, - "maxProperties": 16, - "additionalProperties": false, - "patternProperties": { - "^[0-9a-f]{64}$": { - "$ref": "#/$defs/public_key" - } - } - }, - "evaluator_key_map": { - "type": "object", - "minProperties": 1, - "maxProperties": 32, - "additionalProperties": false, - "patternProperties": { - "^[0-9a-f]{64}$": { - "$ref": "#/$defs/public_key" - } - } - } - } -} diff --git a/core/interprocess_lock.py b/core/interprocess_lock.py deleted file mode 100644 index e90857fc..00000000 --- a/core/interprocess_lock.py +++ /dev/null @@ -1,76 +0,0 @@ -"""Small cross-platform file lock for durable state transactions.""" - -from __future__ import annotations - -import os -import threading -from contextlib import contextmanager -from pathlib import Path -from typing import BinaryIO, Iterator - - -_REGISTRY_GUARD = threading.Lock() -_THREAD_LOCKS: dict[str, threading.RLock] = {} - - -def _shared_thread_lock(path: Path) -> threading.RLock: - key = os.path.normcase(str(path.resolve())) - with _REGISTRY_GUARD: - lock = _THREAD_LOCKS.get(key) - if lock is None: - lock = threading.RLock() - _THREAD_LOCKS[key] = lock - return lock - - -class InterprocessFileLock: - """Serialize one-byte sidecar locks across threads and processes.""" - - def __init__(self, path: Path) -> None: - self.path = Path(path) - self._thread_lock = _shared_thread_lock(self.path) - - @staticmethod - @contextmanager - def _lock_handle(handle: BinaryIO) -> Iterator[None]: - handle.seek(0) - if os.name == "nt": - import msvcrt - - msvcrt.locking(handle.fileno(), msvcrt.LK_LOCK, 1) - try: - yield - finally: - handle.seek(0) - msvcrt.locking(handle.fileno(), msvcrt.LK_UNLCK, 1) - return - - import fcntl - - fcntl.flock( # type: ignore[attr-defined] - handle.fileno(), - fcntl.LOCK_EX, # type: ignore[attr-defined] - ) - try: - yield - finally: - fcntl.flock( # type: ignore[attr-defined] - handle.fileno(), - fcntl.LOCK_UN, # type: ignore[attr-defined] - ) - - @contextmanager - def hold(self) -> Iterator[None]: - with self._thread_lock: - self.path.parent.mkdir(parents=True, exist_ok=True) - with self.path.open("a+b") as handle: - handle.seek(0, os.SEEK_END) - if handle.tell() == 0: - handle.write(b"\0") - handle.flush() - os.fsync(handle.fileno()) - with self._lock_handle(handle): - yield - - -__all__ = ["InterprocessFileLock"] diff --git a/core/logger.py b/core/logger.py index 075faf74..a27bb731 100644 --- a/core/logger.py +++ b/core/logger.py @@ -38,8 +38,7 @@ def emit(self, record: logging.LogRecord): value = repr(value) payload[key] = value if record.exc_info: - formatter = self.formatter or logging.Formatter() - payload["exception"] = formatter.formatException(record.exc_info) + payload["exception"] = self.formatException(record.exc_info) safe = redact(payload) with LOG_FILE.open("a") as f: f.write(json.dumps(safe, default=str) + "\n") diff --git a/core/ontology.py b/core/ontology.py index 960605da..ebae5ae3 100644 --- a/core/ontology.py +++ b/core/ontology.py @@ -60,8 +60,8 @@ class TradeProposalDraft(BaseModel): class HybridReviewResult(BaseModel): task: str - primary: dict[str, Any] - secondary: dict[str, Any] + primary: dict + secondary: dict agreement_score: Decimal confidence_adjustment: Decimal verdict: str @@ -280,15 +280,6 @@ class LiveOrderRequest(BaseModel): # LiveBrokerFirewall rejects omission, while every production constructor # emits an explicit QUANT_ONLY or MODEL_WEIGHTED attestation. model_influence_attestation: Optional[ModelInfluenceAttestation] = None - # Optional only for compatibility with the pre-DumbMoney standalone - # runtime. When a CapitalEnvelopeAdapter is installed at the central - # firewall, all five fields become mandatory and are revalidated at the - # trusted sink immediately before a durable capital reservation. - capital_envelope_id: Optional[str] = None - capital_strategy_hash: Optional[str] = None - capital_passport_hash: Optional[str] = None - capital_promotion_hash: Optional[str] = None - capital_fencing_generation: Optional[int] = None class LiveOrderResult(BaseModel): success: bool diff --git a/core/state.py b/core/state.py index 73d3430f..19645e87 100644 --- a/core/state.py +++ b/core/state.py @@ -1,11 +1,9 @@ import json import os -from collections.abc import Callable from datetime import datetime, timezone from pathlib import Path from uuid import uuid4 -from core.interprocess_lock import InterprocessFileLock from core.ontology import AccountMode, KillSwitchState, EmergencyStopState @@ -28,21 +26,13 @@ def __init__(self, *, persist: bool = False, state_path: Path | None = None): self.balance_cents = 0 configured_path = os.environ.get("DUMMY_RISK_STATE_PATH") self._state_path = state_path or (Path(configured_path) if configured_path else DEFAULT_RISK_STATE_PATH) - self._state_lock = InterprocessFileLock( - self._state_path.with_name(f"{self._state_path.name}.lock") - ) self._persist_enabled = persist self._daily_loss_cents = 0 self._daily_loss_date = datetime.now(timezone.utc).date().isoformat() self._processed_settlements: set[str] = set() self.daily_loss_window_start = datetime.now(timezone.utc) self.persistence_error: str | None = None - # Importing the module must remain read-only. In particular, status - # commands and watchdog inspections must not create a runtime - # directory merely because the singleton is constructed. A missing - # persisted state is handled by the first explicit persistence or - # fail-closed refresh operation. - if self._persist_enabled and self._state_path.exists(): + if self._persist_enabled: self._load_risk_state() @property @@ -54,33 +44,17 @@ def daily_loss_cents(self) -> int: def daily_loss_cents(self, value: int) -> None: self._daily_loss_cents = max(0, int(value)) - def _rollover_memory_if_needed(self) -> bool: + def _rollover_if_needed(self) -> None: if self.persistence_error is not None: - return False + return today = datetime.now(timezone.utc).date().isoformat() if self._daily_loss_date == today: - return False + return self._daily_loss_date = today self._daily_loss_cents = 0 self._processed_settlements.clear() self.daily_loss_window_start = datetime.now(timezone.utc) - return True - - def _rollover_if_needed(self) -> None: - if self.persistence_error is not None: - return - if not self._persist_enabled: - self._rollover_memory_if_needed() - return - try: - with self._state_lock.hold(): - if not self._synchronize_locked(require_existing=False): - return - except Exception as exc: - self._activate_safety_controls_fail_closed( - "persisted risk state lock unavailable" - ) - self.persistence_error = f"{type(exc).__name__}: {exc}" + self._persist_risk_state() def _activate_safety_controls_fail_closed(self, reason: str) -> None: now = datetime.now(timezone.utc) @@ -107,18 +81,14 @@ def _parse_emergency_stop(value: object) -> EmergencyStopState: raise ValueError("active emergency_stop requires triggered_at") return parsed - def _load_risk_state_locked( - self, - *, - require_existing: bool = False, - ) -> tuple[bool, bool]: + def _load_risk_state(self, *, require_existing: bool = False) -> bool: if not self._state_path.exists(): if require_existing: reason = "persisted risk state missing during safety refresh" self._activate_safety_controls_fail_closed(reason) self.persistence_error = f"FileNotFoundError: {reason}" - return False, False - return True, False + return False + return True try: data = json.loads(self._state_path.read_text(encoding="utf-8")) if not isinstance(data, dict): @@ -144,62 +114,43 @@ def _load_risk_state_locked( settlements = data.get("processed_settlement_ids", []) if not isinstance(settlements, list) or not all(isinstance(item, str) for item in settlements): raise ValueError("processed_settlement_ids must be a string list") - # This set is one UTC day's replay boundary. Truncating it lets an - # old settlement be counted again after enough later settlements. - self._processed_settlements = set(settlements) + self._processed_settlements = set(settlements[-10000:]) self.persistence_error = None - return True, migrated_legacy_controls + self._rollover_if_needed() + if migrated_legacy_controls and not self._persist_risk_state(): + return False + return True except Exception as exc: # An unreadable state is not equivalent to zero loss or inactive # safety controls. Both controls latch on in memory and the file is # quarantined until an operator repairs it. self._activate_safety_controls_fail_closed("persisted risk state unreadable") self.persistence_error = f"{type(exc).__name__}: {exc}" - return False, False + return False - def _risk_state_payload(self) -> dict[str, object]: - return { + def _persist_risk_state(self) -> bool: + if not self._persist_enabled: + return True + payload = { "utc_date": self._daily_loss_date, "daily_loss_cents": self._daily_loss_cents, - "processed_settlement_ids": sorted( - self._processed_settlements - ), + "processed_settlement_ids": sorted(self._processed_settlements)[-10000:], "kill_switch": self.kill_switch.model_dump(mode="json"), "emergency_stop": self.emergency_stop.model_dump(mode="json"), "schema_version": RISK_STATE_SCHEMA_VERSION, "updated_at": datetime.now(timezone.utc).isoformat(), } - - def _persist_risk_state_locked(self) -> bool: - if not self._persist_enabled: - return True tmp = self._state_path.with_name( f".{self._state_path.name}.{os.getpid()}.{uuid4().hex}.tmp" ) try: self._state_path.parent.mkdir(parents=True, exist_ok=True) with tmp.open("x", encoding="utf-8") as handle: - json.dump( - self._risk_state_payload(), - handle, - indent=2, - sort_keys=True, - ) + json.dump(payload, handle, indent=2, sort_keys=True) handle.write("\n") handle.flush() os.fsync(handle.fileno()) os.replace(tmp, self._state_path) - with self._state_path.open("r+b") as handle: - os.fsync(handle.fileno()) - if os.name != "nt": - directory_fd = os.open( - self._state_path.parent, - os.O_RDONLY, - ) - try: - os.fsync(directory_fd) - finally: - os.close(directory_fd) self.persistence_error = None return True except Exception as exc: @@ -211,79 +162,16 @@ def _persist_risk_state_locked(self) -> bool: except OSError: pass - def _synchronize_locked(self, *, require_existing: bool) -> bool: - loaded, migrated = self._load_risk_state_locked( - require_existing=require_existing - ) - if not loaded: - return False - rolled_over = self._rollover_memory_if_needed() - if (migrated or rolled_over) and not self._persist_risk_state_locked(): - return False - return True - - def _load_risk_state(self, *, require_existing: bool = False) -> bool: - if not self._persist_enabled: - return True - try: - with self._state_lock.hold(): - return self._synchronize_locked( - require_existing=require_existing - ) - except Exception as exc: - self._activate_safety_controls_fail_closed( - "persisted risk state lock unavailable" - ) - self.persistence_error = f"{type(exc).__name__}: {exc}" - return False - - def _mutate_persisted_state( - self, - mutation: Callable[[], bool], - ) -> bool: - if self.persistence_error is not None: - return False - if not self._persist_enabled: - self._rollover_memory_if_needed() - return mutation() - try: - with self._state_lock.hold(): - if not self._synchronize_locked(require_existing=False): - return False - if not mutation(): - return False - return self._persist_risk_state_locked() - except Exception as exc: - self._activate_safety_controls_fail_closed( - "persisted risk state transaction failed" - ) - self.persistence_error = f"{type(exc).__name__}: {exc}" - return False - def verify_persistence(self) -> bool: - """Reload and rewrite only the exact latest durable snapshot. + """Prove the risk/safety sink is writable without erasing unknown state. - The prior implementation persisted this instance's in-memory fields. - A stale executor could therefore erase a kill switch or newer loss - record written by another process during a pre-submit check. The - locked reload preserves those facts while still proving the actual - target can be atomically replaced. + An earlier load/write failure is a hard stop. In particular, a + corrupt state file must never be overwritten with an optimistic zero + merely because a pre-submit probe ran. """ if self.persistence_error is not None: return False - if not self._persist_enabled: - return True - try: - with self._state_lock.hold(): - if not self._synchronize_locked(require_existing=False): - return False - return self._persist_risk_state_locked() - except Exception as exc: - self._activate_safety_controls_fail_closed( - "persisted risk state writability probe failed" - ) - self.persistence_error = f"{type(exc).__name__}: {exc}" - return False + return self._persist_risk_state() def refresh_persisted_state(self) -> bool: """Reload persisted controls before a live submit. @@ -302,53 +190,41 @@ def record_realized_pnl(self, pnl_cents: int, *, settlement_id: str | None = Non Returns False for a duplicate settlement id. Gains do not erase the daily loss cap, matching the conservative loss-limit semantics. """ + if self.persistence_error is not None: + return False + self._rollover_if_needed() identity = str(settlement_id) if settlement_id else None + if identity and identity in self._processed_settlements: + return False + if identity: + self._processed_settlements.add(identity) + if int(pnl_cents) < 0: + self._daily_loss_cents += -int(pnl_cents) + return self._persist_risk_state() - def mutation() -> bool: - if identity and identity in self._processed_settlements: - return False - if identity: - self._processed_settlements.add(identity) - if int(pnl_cents) < 0: - self._daily_loss_cents += -int(pnl_cents) - return True - - return self._mutate_persisted_state(mutation) - - def set_mode(self, mode: AccountMode) -> None: + def set_mode(self, mode: AccountMode): self.mode = mode - def enable_kill_switch(self, reason: str) -> bool: - def mutation() -> bool: - self.kill_switch = KillSwitchState( - active=True, - triggered_at=datetime.now(timezone.utc), - reason=reason, - ) - return True - - return self._mutate_persisted_state(mutation) + def enable_kill_switch(self, reason: str): + self.kill_switch = KillSwitchState( + active=True, + triggered_at=datetime.now(timezone.utc), + reason=reason, + ) + if self.persistence_error is not None: + # Preserve the quarantined file; never overwrite unknown loss data. + return False + return self._persist_risk_state() - def disable_kill_switch(self) -> bool: + def disable_kill_switch(self): if self.persistence_error is not None: self._activate_safety_controls_fail_closed( "cannot disable kill switch while persisted state is unhealthy" ) return False - expected = self.kill_switch.model_dump(mode="json") - if expected.get("active") is not True: - return False previous = self.kill_switch - - def mutation() -> bool: - nonlocal previous - previous = self.kill_switch - if self.kill_switch.model_dump(mode="json") != expected: - return False - self.kill_switch = KillSwitchState(active=False) - return True - - if self._mutate_persisted_state(mutation): + self.kill_switch = KillSwitchState(active=False) + if self._persist_risk_state(): return True # The durable state still says active (or is unknowable); retain the # conservative in-memory latch if the deactivation write fails. @@ -359,37 +235,25 @@ def mutation() -> bool: ) return False - def trigger_emergency_stop(self) -> bool: - def mutation() -> bool: - self.emergency_stop = EmergencyStopState( - active=True, - triggered_at=datetime.now(timezone.utc), - ) - return True - - return self._mutate_persisted_state(mutation) + def trigger_emergency_stop(self): + self.emergency_stop = EmergencyStopState( + active=True, + triggered_at=datetime.now(timezone.utc), + ) + if self.persistence_error is not None: + return False + return self._persist_risk_state() - def clear_emergency_stop(self) -> bool: + def clear_emergency_stop(self): """Persist an explicit operator reset; never auto-clear on restart.""" if self.persistence_error is not None: self._activate_safety_controls_fail_closed( "cannot clear emergency stop while persisted state is unhealthy" ) return False - expected = self.emergency_stop.model_dump(mode="json") - if expected.get("active") is not True: - return False previous = self.emergency_stop - - def mutation() -> bool: - nonlocal previous - previous = self.emergency_stop - if self.emergency_stop.model_dump(mode="json") != expected: - return False - self.emergency_stop = EmergencyStopState(active=False) - return True - - if self._mutate_persisted_state(mutation): + self.emergency_stop = EmergencyStopState(active=False) + if self._persist_risk_state(): return True self.emergency_stop = previous if previous.active else EmergencyStopState( active=True, diff --git a/docs/DUMBMONEY_INTEGRATION.md b/docs/DUMBMONEY_INTEGRATION.md deleted file mode 100644 index e6c401e1..00000000 --- a/docs/DUMBMONEY_INTEGRATION.md +++ /dev/null @@ -1,236 +0,0 @@ -# DumbMoney Core integration - -Dummy remains the sovereign Kalshi venue cell. DumbMoney supplies an -additional signed ceiling; it does not supply a live session, enable -`configs/live_submit.json`, change local caps, resolve credentials, or bypass -`LiveBrokerFirewall`. - -## Wire contract - -`CapitalEnvelopeAdapter` verifies: - -- `dumbmoney.signed-envelope.v1` using Ed25519 over canonical JSON of every - wrapper field except `signature`; -- unpadded URL-safe base64 signatures and a signer key ID equal to the - lowercase SHA-256 of the raw 32-byte public key; -- an event ID equal to the lowercase SHA-256 of canonical wrapper fields - excluding `event_id` and `signature`; -- a `dumbmoney.capital-envelope.v1` body whose digest, venue, account hash, - equal-count strategy/passport/promotion hashes, exact broker instrument IDs, - UTC window, policy epoch, and integer-cent limits all match exactly; -- strictly increasing source sequence and global fencing generation, with a - maximum-ever fence high-water mark so an older lease cannot revive after a - newer lease expires; -- `max_order_risk_cents <= max_correlated_risk_cents <= - max_open_risk_cents`, plus enough remaining daily-loss capacity for the - proposed order rather than only checking whether the prior loss reached the - ceiling. - -The cross-repository fixture is mirrored at -`tests/fixtures/dumbmoney/signed-capital-envelope.v1.json`. It contains a -public key and signed envelope but no private key. - -## Local authority intersection - -When an adapter is installed on `LiveBrokerFirewall`, a request must carry the -exact envelope ID, strategy hash, passport hash, promotion hash, and fencing -generation. Dummy derives `event_contract:` at the -trusted sink and requires that exact identifier in `authorized_instruments`; -prefixes, classes, and globs do not authorize an order. -Dummy evaluates all existing local risk, authority, allowlist, exposure, -frequency, and order caps first. The signed grant is then evaluated as another -deny-only ceiling. Both the external reservation and Dummy's existing -exposure reservation must persist before the broker transport can be called. - -The adapter is opt-in at construction so the standalone Dummy runtime remains -backward compatible. Supplying capital-binding fields without an installed -adapter fails closed. - -## Broker bootstrap and journal - -An adapter cannot reserve risk until it has a fresh, account-bound broker -bootstrap receipt: - -- `dummy.broker-bootstrap.flat.v1` proves a broker-observed empty order and - position book. -- `dummy.broker-bootstrap.inherited-exposure.v1` records inherited open risk - and consumes the signed grant before any new request. - -No receipt means unknown exposure, never a flat account. Observations must be -strictly increasing and are bound to a broker-snapshot digest. - -Production uses indexed SQLite WAL journals with `synchronous=FULL`, -`BEGIN IMMEDIATE` cross-process conditional appends, immutable-event -triggers, an event hash chain, bounded indexed kind/outbox reads, and a full -rescan whenever SQLite reports an external data-version change. The -broker-bootstrap and command-feed polling hot paths validate only their -indexed latest kinds, so five-second polling does not repeatedly materialize -the full journal. JSONL remains a compatibility implementation for isolated -tests, not the Windows service hot path. - -An internal database hash chain cannot detect replacement with an older, -byte-for-byte valid database image. The runner therefore anchors three exact -local heads in Core's independently persisted signed ledger: -`capital-operational`, `command-feed`, and the revisioned semantic digest of -`live-exposure`. Each stream is account-, schema-, and name-bound. Core rejects -a lower sequence or a different digest at the same sequence. Dummy verifies -the Core envelope, independently recomputes the ledger-event proof, verifies a -fresh Core-signed request-bound checkpoint, and anchors before broker reads and -again after cycle mutations. A rollback cannot regain execution readiness. - -Caller-authored local-failure receipts cannot release a capital reservation. -Terminal order and settlement recovery instead require typed, service-signed -broker witnesses exactly bound to the dispatch claim, account, subaccount, -client order ID, broker order ID, order terms, terminal state, observation -window, and local exposure projection. Ambiguous outcomes remain reserved; -filled capital is released only after venue exposure is projected, and that -position exposure remains until a stable position-absence read plus a matching -settlement witness. - -## Core contract authority - -Each passport and promotion resolution must include the frozen -`dumbmoney.cell-authority-state.v1` projection inside the Core-signed -checkpoint. Dummy verifies current kill-clear and LIVE desired mode, policy -and mandate identity, capital/fence/strategy/passport/promotion bindings, -capital and contract ledger-event continuity, at least two unique current -PASS facts from at least two courts, and evaluator signer IDs from a sealed -role-disjoint keyring. Promotion and passport must resolve from the same -authority state. The binding expires at the earliest contract, capital, or -`authority_valid_until` boundary and is resolved again at final use. - -## Core command feed - -`CoreCommandFeedConsumer` is an injected, local-only `poll_once` API. It has -no HTTP client, retry loop, scheduler, background thread, broker writer, or -import-time side effect. A supervised runner must inject: - -- a GET-only loopback transport for - `/v1/cells/dummy_kalshi/commands?after=N&cursor=&limit=L`; -- an OS-secret-backed `dummy_kalshi` cell bearer provider distinct from the - operator token; -- a sealed release-role bundle containing disjoint pinned keyrings: Core keys - for page checkpoints and capital grants, and operator keys for kill and - desired-mode envelopes; -- the account-pinned capital adapter and a separate operational journal for - feed state; -- idempotent authority-reducing handlers that assert local KILL or PAUSE. - -The consumer first verifies the Core Ed25519 signature over the exact -`dumbmoney.cell-command-checkpoint.v1` canonical JSON. Every top-level cursor, -head digest, observation time, required action, and ordered command projection -must byte-canonically mirror that checkpoint. `has_more` is derived from the -signed next/head sequences rather than trusted as an unsigned assertion. -Each poll generates 32 cryptographically random bytes and sends the lowercase -hex value as `request_nonce`; the same value must appear in the page and its -signed checkpoint. A captured response therefore cannot satisfy a later -request even while its observation timestamp remains fresh. A repeated or -noncanonical locally generated nonce fails before any GET. -Every projected `dumbmoney.ledger-event-proof.v1` is also checked -independently: its payload digest must bind the envelope body, all duplicated -identity and provenance fields must agree, its event digest is recomputed, and -observable adjacent global/source chain links must extend the known cursor. - -Each kill or desired-mode envelope must then verify under the operator -keyring; each capital envelope must verify under the Core keyring. The -keyrings are required to be disjoint and every key ID must equal the SHA-256 -of its raw Ed25519 public key. A valid signature under the wrong role is still -rejected. - -The consumer persists `(next_sequence, next_digest)` and the resulting -controls in one fsynced journal event. Its append also compares the expected -starting cursor under the interprocess writer lock, so two runners cannot both -commit from one cursor. A backlog (`has_more=true`), -authentication/transport failure, stale or future signed checkpoint, unknown -schema or signer, cursor mismatch, projection/proof tamper, or dispatch failure -remains fail-closed. One call performs at most one GET and never retries a -write. - -Historical signed events still advance the durable cursor. Expired -kill-active and non-LIVE mode events remain authority-reducing and persist. -Expired or future kill-clear, LIVE-mode, and capital grants update only their -monotonic high-water marks and never activate authority. Unsigned -page fields cannot change the checkpoint-signed `required_action`, and even a -valid signed positive action can never clear a local kill latch. -`has_more` requires another explicit `poll_once`; there is no autonomous drain -loop. - -## Kalshi write boundary - -The central firewall constructs the current event-order V2 wire shape and -uses `POST /portfolio/events/orders`: one YES-denominated `bid`/`ask` book, -fixed-point `count` and `price` strings, explicit time-in-force, -self-trade prevention, subaccount zero, pause cancellation, and `post_only` -for makers. Buying NO maps to an ask at the complementary YES price. The -transport capability gate recognizes both the V2 collection and the legacy -collection so the new route cannot bypass the chokepoint. - -A write waits for its private mutation lane before the final Core resolution, -then consumes a single-use permit before exactly one socket attempt. -Timeouts, request errors, HTTP 429, malformed acknowledgements, and immediate -fill/remainder projections are ambiguous outcomes: they are never resent and -retain the deterministic `client_order_id` reservation for reconciliation. -The default production REST origin is -`https://external-api.kalshi.com/trade-api/v2`. Conflicting ambient -host/version overrides are rejected, HTTP clients do not inherit proxy or -netrc settings, and broker JSON is decoded as bounded strict UTF-8 with -duplicate keys and non-finite numbers rejected. - -## Kill and cancellation behavior - -Queueing kill reconciliation can mirror `authority.cancel_only` into the -operational journal. This always removes submission authority. It does not -create cancellation authority or contact Kalshi. A cancel-reconciliation -command is written to the outbox only when a distinct existing -cancellation-authority receipt is supplied. - -## Activation status - -The sealed Windows runner, public config schema/template, Credential Manager -targets, signed readiness, Core command/contract transports, and SQLite -journals exist. The production runner now constructs a credential-owned, -read-only Kalshi truth provider without exporting its RSA key or key ID into -the process environment. The provider pins -`https://external-api.kalshi.com/trade-api/v2`, disables ambient proxy and -redirect behavior, signs only the documented balance, positions, and resting -orders GET paths, bounds every response, and performs no retry. Reconciliation -also reads the documented current and historical order/fill tiers plus -settlements so archival movement cannot manufacture an absent order or fill. -Positions, orders, fills, and settlements are fully paginated, constrained to -subaccount `0`, then read twice; any cursor truncation, duplicate identity, -cross-subaccount row, schema drift, aggregate disagreement, or change between -the two projections fails closed. The stable fixed-point projection is -recorded in both the local and Core-capital exposure domains. - -Every reservation now includes the submitted notional plus the general -worst-case Kalshi taker fee, including post-only maker intents. A terminal -broker observation is accepted only as a typed, domain-separated witness -signed by the sealed Dummy service identity and tied to the exact reservation, -account, subaccount, order, fills, observation window, and projection digest. -The restart-safe sweeper first idempotently projects fills into venue-local -exposure, then releases the order reservation. Filled exposure remains -reserved independently until a second stable position-absence read and -matching settlement witness have been persisted. These service signatures -attest which local service observed the authenticated broker response; they do -not imply that Kalshi signed the response. - -The service still intentionally starts and remains -`RECONCILIATION_ONLY`. Production installs -`SealedDisabledExecutionCycle`, which accepts the exact broker snapshot and -returns its digest but owns no broker client, credential, callback, or submit -method. It always returns `BLOCKED`, `broker_contacted=false`, and -`orders_submitted=0`. This proves the production cycle boundary and snapshot -binding without creating order authority. - -Live activation is blocked until all of the following are sealed and tested -end to end: - -- a real authenticated target-account validation of the implemented, - fully-paginated double-read broker and reconciliation projections; -- a separately reviewed, sealed order-capable execution adapter replacing the - disabled harness while preserving the exact verified broker-snapshot digest; -- witnessed place/reconcile/settle/kill/restart drills against the intended - account, beginning with an attended mechanical canary. - -Do not interpret signed readiness, passing unit tests, or a fresh flat-book -receipt as live authorization or profitability evidence. diff --git a/kalshi/client.py b/kalshi/client.py index f73f5129..3315811d 100644 --- a/kalshi/client.py +++ b/kalshi/client.py @@ -11,13 +11,10 @@ from kalshi.signer import sign_request from kalshi.error_classifier import classify from kalshi.rate_limiter import KalshiRateLimiter -from kalshi.strict_json import load_strict_json_response from core.logger import logger _REQUEST_TIMEOUT_SECONDS = 10 _REQUEST_OUTER_TIMEOUT_SECONDS = 10 -_KALSHI_PRODUCTION_ORIGIN = "https://external-api.kalshi.com" -_KALSHI_PRODUCTION_VERSION = "trade-api/v2" # Raw write methods are transport primitives, not public execution surfaces. # The identity token is deliberately private and is presented only by the @@ -27,16 +24,6 @@ _READ_ONLY_HTTP_METHODS = frozenset({"GET", "HEAD", "OPTIONS"}) -class _OneShotMutationPermit: - """Opaque, client-owned permit consumed by exactly one mutation attempt.""" - - __slots__ = ("method", "path") - - def __init__(self, method: str, path: str) -> None: - self.method = method - self.path = path - - def _canonical_path_segments(path: str) -> tuple[str, ...]: """Return decoded, dot-normalized URL path segments for safety checks.""" raw_path = urlsplit(str(path)).path.replace("\\", "/") @@ -68,37 +55,18 @@ def _is_order_mutation(method: str, path: str) -> bool: segments = _canonical_path_segments(path) return any( segments[index : index + 2] == ("portfolio", "orders") - or segments[index : index + 3] - == ("portfolio", "events", "orders") for index in range(max(0, len(segments) - 1)) ) -# The production transport is deliberately not configurable through ambient -# environment variables. A service environment inherited from another process -# must never be able to redirect an authenticated request to a different host -# or change the path prefix after deployment review. +# Defaults must stay aligned with kalshi.signer so the signed path prefix and +# the request URL agree. The legacy v1 host (trading-api.kalshi.com) is dead. def _kalshi_base() -> str: - return _KALSHI_PRODUCTION_ORIGIN + return os.environ.get("KALSHI_API_BASE", "https://api.elections.kalshi.com").rstrip("/") def _kalshi_version() -> str: - return _KALSHI_PRODUCTION_VERSION - - -def _reject_ambient_endpoint_redirect() -> None: - configured_base = os.environ.get("KALSHI_API_BASE") - if ( - configured_base is not None - and configured_base.rstrip("/") != _KALSHI_PRODUCTION_ORIGIN - ): - raise RuntimeError("KALSHI_ENDPOINT_OVERRIDE_REJECTED") - configured_version = os.environ.get("KALSHI_API_VERSION") - if ( - configured_version is not None - and configured_version.strip("/") != _KALSHI_PRODUCTION_VERSION - ): - raise RuntimeError("KALSHI_ENDPOINT_OVERRIDE_REJECTED") + return os.environ.get("KALSHI_API_VERSION", "trade-api/v2").strip("/") # Backward-compatible module-level aliases for code that reads them at import time. @@ -107,84 +75,10 @@ def _reject_ambient_endpoint_redirect() -> None: class KalshiClient: - def __init__(self) -> None: - _reject_ambient_endpoint_redirect() - self.client = httpx.AsyncClient( - base_url=f"{_kalshi_base()}/{_kalshi_version()}", - timeout=_REQUEST_TIMEOUT_SECONDS, - trust_env=False, - ) + def __init__(self): + self.client = httpx.AsyncClient(base_url=f"{_kalshi_base()}/{_kalshi_version()}", timeout=_REQUEST_TIMEOUT_SECONDS) self.limiter = KalshiRateLimiter() self.request_audit_log: deque[dict[str, Any]] = deque(maxlen=1000) - self._mutation_lock = asyncio.Lock() - self._active_mutation_permit: _OneShotMutationPermit | None = None - - async def prepare_order_mutation( - self, - method: str, - path: str, - *, - _capability: object | None = None, - ) -> object: - """Wait for the mutation lane before the caller's final authority check. - - The permit is deliberately opaque and single-use. It serializes writes - without placing a limiter wait between the final Core resolution and - the socket send. - """ - if ( - _capability is not _CENTRAL_FIREWALL_SUBMIT_CAPABILITY - or not _is_order_mutation(method, path) - ): - raise PermissionError( - "DIRECT_ORDER_SUBMIT_RETIRED_USE_CENTRAL_LIVE_FIREWALL" - ) - await self._mutation_lock.acquire() - permit = _OneShotMutationPermit( - str(method).strip().upper(), - "/" + "/".join(_canonical_path_segments(path)), - ) - self._active_mutation_permit = permit - return permit - - def cancel_prepared_order_mutation( - self, - permit: object, - *, - _capability: object | None = None, - ) -> None: - """Release an unused permit when final authority fails closed.""" - if ( - _capability is not _CENTRAL_FIREWALL_SUBMIT_CAPABILITY - or permit is not self._active_mutation_permit - ): - raise PermissionError("INVALID_ORDER_MUTATION_PERMIT") - self._active_mutation_permit = None - self._mutation_lock.release() - - def _consume_mutation_permit( - self, - permit: object, - *, - method: str, - path: str, - ) -> None: - normalized_method = str(method).strip().upper() - normalized_path = "/" + "/".join(_canonical_path_segments(path)) - if ( - permit is not self._active_mutation_permit - or not isinstance(permit, _OneShotMutationPermit) - or permit.method != normalized_method - or permit.path != normalized_path - ): - raise PermissionError("INVALID_ORDER_MUTATION_PERMIT") - # Invalidate before transport so the same object can never authorize a - # retry, including after a timeout or an HTTP 429. - self._active_mutation_permit = None - - def _finish_mutation_attempt(self) -> None: - if self._mutation_lock.locked(): - self._mutation_lock.release() def _family_path(self, path: str) -> str: """Collapse ticker-specific segments so `/markets/FOO/orderbook` becomes `/markets/{ticker}/orderbook`.""" @@ -194,56 +88,32 @@ def _family_path(self, path: str) -> str: if len(parts) >= 3 and parts[0] == "portfolio" and parts[1] == "orders": if not parts[2].startswith("{"): parts[2] = "{order_id}" - if ( - len(parts) >= 4 - and parts[0] == "portfolio" - and parts[1] == "events" - and parts[2] == "orders" - and not parts[3].startswith("{") - and parts[3] != "batched" - ): - parts[3] = "{order_id}" return "/" + "/".join(parts) def _redacted_summary(self, response: httpx.Response) -> dict[str, Any]: summary: dict[str, Any] = {"status_code": response.status_code} if response.status_code < 400: try: - data = load_strict_json_response(response) + data = response.json() if isinstance(data, list): summary["count"] = len(data) elif isinstance(data, dict): summary["keys"] = sorted(data.keys())[:10] - values = list(data.values()) - summary["count"] = ( - len(data) - if values and isinstance(values[0], list) - else None - ) + summary["count"] = len(data) if isinstance(list(data.values())[0], list) else None except Exception: summary["body_preview"] = response.text[:120] else: summary["error_preview"] = response.text[:120] return summary - async def _request( - self, - method: str, - path: str, - **kwargs: Any, - ) -> Any: + async def _request(self, method: str, path: str, **kwargs): capability = kwargs.pop("_capability", None) - mutation = _is_order_mutation(method, path) - mutation_permit = kwargs.pop("_mutation_permit", None) - if mutation: - if capability is not _CENTRAL_FIREWALL_SUBMIT_CAPABILITY: - raise PermissionError( - "DIRECT_ORDER_SUBMIT_RETIRED_USE_CENTRAL_LIVE_FIREWALL" - ) - self._consume_mutation_permit( - mutation_permit, - method=method, - path=path, + if ( + _is_order_mutation(method, path) + and capability is not _CENTRAL_FIREWALL_SUBMIT_CAPABILITY + ): + raise PermissionError( + "DIRECT_ORDER_SUBMIT_RETIRED_USE_CENTRAL_LIVE_FIREWALL" ) json_body = kwargs.pop("json", "") if isinstance(json_body, dict): @@ -255,49 +125,35 @@ async def _request( else: body_str = "" body_bytes = b"" - try: - headers = sign_request(method, path, body_str) - headers["Content-Type"] = "application/json" - - async def call() -> Any: - response = await self.client.request(method, path, headers=headers, content=body_bytes, **kwargs) - self.request_audit_log.append({ - "method": method.upper(), - "path": path, - "path_family": self._family_path(path), - "status_code": response.status_code, - "status_class": f"{response.status_code // 100}xx", - "redacted_summary": self._redacted_summary(response), - }) - if response.status_code >= 400: - cat = classify(response.status_code, response.text) - logger.error("Kalshi API error", extra={"component": "kalshi_client", "status": response.status_code, "category": cat.value}) - response.raise_for_status() - return load_strict_json_response(response) - - # A mutation is exactly one socket attempt. Any timeout, - # RequestError, or HTTP error is an ambiguous broker outcome and - # must be reconciled by deterministic client_order_id, never sent - # again. Read-only requests retain bounded retry behavior. - if mutation: - return await asyncio.wait_for( - call(), - timeout=_REQUEST_OUTER_TIMEOUT_SECONDS, - ) - loop = asyncio.get_running_loop() - deadline = loop.time() + _REQUEST_OUTER_TIMEOUT_SECONDS - 0.05 - return await asyncio.wait_for( - self.limiter.execute(call, deadline=deadline), - timeout=_REQUEST_OUTER_TIMEOUT_SECONDS, - ) - finally: - if mutation: - self._finish_mutation_attempt() + headers = sign_request(method, path, body_str) + headers["Content-Type"] = "application/json" + async def call(): + response = await self.client.request(method, path, headers=headers, content=body_bytes, **kwargs) + self.request_audit_log.append({ + "method": method.upper(), + "path": path, + "path_family": self._family_path(path), + "status_code": response.status_code, + "status_class": f"{response.status_code // 100}xx", + "redacted_summary": self._redacted_summary(response), + }) + if response.status_code >= 400: + cat = classify(response.status_code, response.text) + logger.error("Kalshi API error", extra={"component": "kalshi_client", "status": response.status_code, "category": cat.value}) + response.raise_for_status() + return response.json() + # Hard outer bound so no Kalshi request can block the caller indefinitely. + loop = asyncio.get_running_loop() + deadline = loop.time() + _REQUEST_OUTER_TIMEOUT_SECONDS - 0.05 + return await asyncio.wait_for( + self.limiter.execute(call, deadline=deadline), + timeout=_REQUEST_OUTER_TIMEOUT_SECONDS, + ) - async def get_events(self) -> Any: + async def get_events(self): return await self._request("GET", "/events") - async def get_markets(self, max_pages: int = 10) -> Any: + async def get_markets(self, max_pages: int = 10): combined: list[Any] = [] cursor: str | None = None first_page: dict[str, Any] | None = None @@ -327,13 +183,13 @@ async def get_markets(self, max_pages: int = 10) -> Any: result["pagination_truncated"] = cursor is not None return result - async def get_event(self, ticker: str) -> Any: + async def get_event(self, ticker: str): return await self._request("GET", f"/events/{ticker}") - async def get_series(self, ticker: str) -> Any: + async def get_series(self, ticker: str): return await self._request("GET", f"/series/{ticker}") - async def get_market(self, ticker: str) -> Any: + async def get_market(self, ticker: str): return await self._request("GET", f"/markets/{ticker}") async def get_orderbook(self, ticker: str, depth: int = 10) -> OrderBook: @@ -402,35 +258,28 @@ async def get_orderbook(self, ticker: str, depth: int = 10) -> OrderBook: }, ) - async def get_account(self) -> Any: + async def get_account(self): return await self._request("GET", "/portfolio/balance") - async def get_positions(self) -> Any: + async def get_positions(self): return await self._request("GET", "/portfolio/positions") - async def get_fills(self) -> Any: + async def get_fills(self): return await self._request("GET", "/portfolio/fills") - async def get_orders(self) -> Any: + async def get_orders(self): return await self._request("GET", "/portfolio/orders") - async def create_order( - self, - order: dict[str, Any], - *, - _capability: object | None = None, - _mutation_permit: object | None = None, - ) -> Any: + async def create_order(self, order: dict, *, _capability: object | None = None): if _capability is not _CENTRAL_FIREWALL_SUBMIT_CAPABILITY: raise PermissionError( "DIRECT_ORDER_SUBMIT_RETIRED_USE_CENTRAL_LIVE_FIREWALL" ) return await self._request( "POST", - "/portfolio/events/orders", + "/portfolio/orders", json=order, _capability=_capability, - _mutation_permit=_mutation_permit, ) async def cancel_order( @@ -438,14 +287,12 @@ async def cancel_order( order_id: str, *, _capability: object | None = None, - _mutation_permit: object | None = None, - ) -> Any: + ): return await self._request( "DELETE", - f"/portfolio/events/orders/{order_id}", + f"/portfolio/orders/{order_id}", _capability=_capability, - _mutation_permit=_mutation_permit, ) - async def close(self) -> None: + async def close(self): await self.client.aclose() diff --git a/kalshi/signer.py b/kalshi/signer.py index 67e97667..2438ad18 100644 --- a/kalshi/signer.py +++ b/kalshi/signer.py @@ -5,16 +5,12 @@ from cryptography.hazmat.primitives import serialization, hashes from cryptography.hazmat.primitives.asymmetric import padding -_KALSHI_PRODUCTION_ORIGIN = "https://external-api.kalshi.com" -_KALSHI_PRODUCTION_VERSION = "trade-api/v2" - - def _kalshi_base() -> str: - return _KALSHI_PRODUCTION_ORIGIN + return os.environ.get("KALSHI_API_BASE", "https://api.elections.kalshi.com").rstrip("/") def _kalshi_version() -> str: - return _KALSHI_PRODUCTION_VERSION + return os.environ.get("KALSHI_API_VERSION", "trade-api/v2").strip("/") # Backward-compatible module-level aliases for code that reads them at import time. diff --git a/kalshi/strict_json.py b/kalshi/strict_json.py deleted file mode 100644 index 93c49715..00000000 --- a/kalshi/strict_json.py +++ /dev/null @@ -1,77 +0,0 @@ -"""Bounded strict JSON decoding for untrusted Kalshi HTTP responses.""" - -from __future__ import annotations - -import json -import math -from typing import Any, Protocol - -MAX_KALSHI_JSON_RESPONSE_BYTES = 8 * 1024 * 1024 - - -class StrictJSONResponseError(ValueError): - """Raised when a broker response is not bounded strict UTF-8 JSON.""" - - -class _ByteResponse(Protocol): - @property - def content(self) -> bytes: ... - - -def _reject_duplicate_keys(pairs: list[tuple[str, Any]]) -> dict[str, Any]: - value: dict[str, Any] = {} - for key, item in pairs: - if key in value: - raise StrictJSONResponseError( - "Kalshi response contains duplicate JSON keys" - ) - value[key] = item - return value - - -def _reject_non_finite(token: str) -> None: - raise StrictJSONResponseError( - f"Kalshi response contains non-finite JSON value {token}" - ) - - -def _parse_finite_float(token: str) -> float: - value = float(token) - if not math.isfinite(value): - _reject_non_finite(token) - return value - - -def load_strict_json_response( - response: _ByteResponse, - *, - maximum_bytes: int = MAX_KALSHI_JSON_RESPONSE_BYTES, -) -> Any: - """Decode one fully buffered response without permissive JSON extensions.""" - if not isinstance(maximum_bytes, int) or isinstance(maximum_bytes, bool): - raise TypeError("maximum_bytes must be an integer") - if maximum_bytes <= 0: - raise ValueError("maximum_bytes must be positive") - - body = response.content - if not isinstance(body, bytes): - raise StrictJSONResponseError("Kalshi response body must be bytes") - if len(body) > maximum_bytes: - raise StrictJSONResponseError( - f"Kalshi response exceeds {maximum_bytes} byte limit" - ) - - try: - text = body.decode("utf-8", errors="strict") - return json.loads( - text, - object_pairs_hook=_reject_duplicate_keys, - parse_constant=_reject_non_finite, - parse_float=_parse_finite_float, - ) - except StrictJSONResponseError: - raise - except (UnicodeDecodeError, json.JSONDecodeError) as exc: - raise StrictJSONResponseError( - "Kalshi response is not valid strict UTF-8 JSON" - ) from exc diff --git a/live_firewall/dumbmoney_broker_witness.py b/live_firewall/dumbmoney_broker_witness.py deleted file mode 100644 index 4011385f..00000000 --- a/live_firewall/dumbmoney_broker_witness.py +++ /dev/null @@ -1,101 +0,0 @@ -"""Domain-separated signatures for authenticated DumbMoney broker evidence. - -Kalshi authenticates the caller and TLS protects the response in transit, but -portfolio responses are not themselves exchange-signed artifacts. The venue -service therefore signs the exact normalized response projection immediately -after its stable authenticated reads. The signature proves which sealed -service identity observed the broker response; it does not turn local -assertions into exchange facts. -""" - -from __future__ import annotations - -import base64 -import hashlib -from datetime import datetime, timedelta, timezone -from typing import Any, Mapping - -from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey - -from live_firewall.operational_journal import canonical_json, sha256_json - - -SIGNED_ENVELOPE_SCHEMA = "dumbmoney.signed-envelope.v1" -BROKER_WITNESS_SOURCE_ID = "dummy-kalshi-broker-witness" -TERMINAL_WITNESS_SCHEMA = "dummy.kalshi-order-terminal-witness.v1" -SETTLEMENT_WITNESS_SCHEMA = "dummy.kalshi-settlement-witness.v1" -WITNESS_TTL = timedelta(minutes=5) -_ALLOWED_SCHEMAS = frozenset( - {TERMINAL_WITNESS_SCHEMA, SETTLEMENT_WITNESS_SCHEMA} -) - - -def _format_utc(value: datetime) -> str: - rendered = value.astimezone(timezone.utc).isoformat( - timespec="microseconds" if value.microsecond else "seconds" - ) - return rendered.replace("+00:00", "Z") - - -def sign_broker_witness( - body: Mapping[str, Any], - *, - private_key: Ed25519PrivateKey, - observed_at: datetime, - correlation_id: str, -) -> dict[str, Any]: - """Sign one canonical typed witness with the venue-service identity.""" - if ( - observed_at.tzinfo is None - or observed_at.utcoffset() is None - ): - raise ValueError("broker witness clock must be timezone-aware") - value = dict(body) - schema = value.get("schema") - if schema not in _ALLOWED_SCHEMAS: - raise ValueError("broker witness body schema is unsupported") - if not isinstance(correlation_id, str) or not correlation_id: - raise ValueError("broker witness correlation id is required") - observed = observed_at.astimezone(timezone.utc) - not_before = _format_utc(observed) - expires_at = _format_utc(observed + WITNESS_TTL) - public_key = private_key.public_key().public_bytes_raw() - signer_key_id = hashlib.sha256(public_key).hexdigest() - body_digest = sha256_json(value) - event_material = { - "schema": SIGNED_ENVELOPE_SCHEMA, - "source_id": BROKER_WITNESS_SOURCE_ID, - "source_sequence": max(1, int(observed.timestamp() * 1_000_000)), - "correlation_id": correlation_id, - "causation_id": None, - "nonce": body_digest, - "not_before": not_before, - "expires_at": expires_at, - "body_schema": schema, - "body_digest": body_digest, - "body": value, - "signature_algorithm": "Ed25519", - "signer_key_id": signer_key_id, - } - wrapper = { - **event_material, - "event_id": sha256_json(event_material), - } - wrapper["signature"] = ( - base64.urlsafe_b64encode( - private_key.sign(canonical_json(wrapper).encode("utf-8")) - ) - .decode("ascii") - .rstrip("=") - ) - return wrapper - - -__all__ = [ - "BROKER_WITNESS_SOURCE_ID", - "SETTLEMENT_WITNESS_SCHEMA", - "SIGNED_ENVELOPE_SCHEMA", - "TERMINAL_WITNESS_SCHEMA", - "WITNESS_TTL", - "sign_broker_witness", -] diff --git a/live_firewall/dumbmoney_capital.py b/live_firewall/dumbmoney_capital.py deleted file mode 100644 index 741052eb..00000000 --- a/live_firewall/dumbmoney_capital.py +++ /dev/null @@ -1,2623 +0,0 @@ -"""DumbMoney signed capital-envelope adapter for Dummy's local firewall. - -The adapter is venue-neutral at the wire level and configured here for a -specific expected venue/account. A valid grant is only an additional upper -bound. It cannot enable live submission, alter Dummy's local caps, provide -broker credentials, or establish cancellation authority. -""" -from __future__ import annotations - -import base64 -import hashlib -import json -import re -from collections.abc import Callable, Mapping -from dataclasses import dataclass, replace -from datetime import datetime, timedelta, timezone -from typing import Any, Protocol - -from cryptography.exceptions import InvalidSignature -from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey - -from autonomy.fees import kalshi_taker_fee_cents -from live_firewall.dumbmoney_broker_witness import ( - BROKER_WITNESS_SOURCE_ID, - SETTLEMENT_WITNESS_SCHEMA, - TERMINAL_WITNESS_SCHEMA, - WITNESS_TTL, -) -from live_firewall.operational_journal import ( - AppendOnlyOperationalJournal, - OperationalJournalError, - canonical_json, - sha256_json, -) - - -SIGNED_ENVELOPE_SCHEMA = "dumbmoney.signed-envelope.v1" -CAPITAL_ENVELOPE_SCHEMA = "dumbmoney.capital-envelope.v1" -FLAT_BOOTSTRAP_SCHEMA = "dummy.broker-bootstrap.flat.v1" -INHERITED_BOOTSTRAP_SCHEMA = "dummy.broker-bootstrap.inherited-exposure.v1" -CAPITAL_RESERVATION_SCHEMA = "dummy.capital-reservation.v1" -CAPITAL_DISPATCH_CLAIM_SCHEMA = "dummy.capital-dispatch-claim.v1" -CAPITAL_POSITION_EXPOSURE_SCHEMA = "dummy.capital-position-exposure.v1" -CAPITAL_TERMINAL_RELEASE_SCHEMA = "dummy.capital-terminal-release.v1" -CAPITAL_POSITION_RELEASE_SCHEMA = "dummy.capital-position-release.v1" -_SHA256_RE = re.compile(r"^[0-9a-f]{64}$") -_IDENTIFIER_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$") -_RFC3339_UTC_RE = re.compile( - r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,6})?Z$" -) - - -def _utc_now() -> datetime: - return datetime.now(timezone.utc) - - -def _parse_utc(value: Any, *, field: str) -> datetime: - if not isinstance(value, str) or not _RFC3339_UTC_RE.fullmatch(value): - raise ValueError(f"{field} must be canonical RFC3339 UTC") - parsed = datetime.fromisoformat(value[:-1] + "+00:00") - if parsed.tzinfo is None: - raise ValueError(f"{field} must be timezone-aware") - return parsed.astimezone(timezone.utc) - - -def _require_text(value: Any, *, field: str) -> str: - if not isinstance(value, str) or not value.strip() or value != value.strip(): - raise ValueError(f"{field} must be a nonblank canonical string") - return value - - -def _require_identifier(value: Any, *, field: str) -> str: - if not isinstance(value, str) or not _IDENTIFIER_RE.fullmatch(value): - raise ValueError(f"{field} must be a canonical identifier") - return value - - -def _require_sha256(value: Any, *, field: str) -> str: - if not isinstance(value, str) or not _SHA256_RE.fullmatch(value): - raise ValueError(f"{field} must be a lowercase sha256") - return value - - -def _require_int(value: Any, *, field: str, minimum: int = 0) -> int: - if isinstance(value, bool) or not isinstance(value, int) or value < minimum: - raise ValueError(f"{field} must be an integer >= {minimum}") - return value - - -def _require_hashes(value: Any, *, field: str) -> tuple[str, ...]: - if not isinstance(value, list) or not value: - raise ValueError(f"{field} must be a nonempty sorted list") - normalized = tuple(_require_sha256(item, field=field) for item in value) - if list(normalized) != sorted(set(normalized)): - raise ValueError(f"{field} must be sorted and unique") - return normalized - - -def _require_identifiers(value: Any, *, field: str) -> tuple[str, ...]: - if not isinstance(value, list) or not value: - raise ValueError(f"{field} must be a nonempty sorted list") - normalized = tuple( - _require_identifier(item, field=f"{field}[]") for item in value - ) - if list(normalized) != sorted(set(normalized)): - raise ValueError(f"{field} must be sorted and unique") - return normalized - - -def _decode_base64url_no_padding(value: Any, *, field: str) -> bytes: - if not isinstance(value, str) or not value or "=" in value: - raise ValueError(f"{field} must be unpadded base64url") - if re.search(r"[^A-Za-z0-9_-]", value): - raise ValueError(f"{field} must be unpadded base64url") - try: - decoded = base64.urlsafe_b64decode(value + "=" * (-len(value) % 4)) - except Exception as exc: - raise ValueError(f"{field} is invalid base64url") from exc - encoded = base64.urlsafe_b64encode(decoded).decode("ascii").rstrip("=") - if encoded != value: - raise ValueError(f"{field} is not canonical base64url") - return decoded - - -def _public_key_bytes(value: bytes | Ed25519PublicKey) -> bytes: - if isinstance(value, Ed25519PublicKey): - return bytes(value.public_bytes_raw()) - raw = bytes(value) - if len(raw) != 32: - raise ValueError("Ed25519 public key must be 32 bytes") - return raw - - -def strategy_binding_hash(reference: str) -> str: - """Bind an existing proof/passport reference without changing its schema.""" - return hashlib.sha256(reference.encode("utf-8")).hexdigest() - - -@dataclass(frozen=True) -class VerifiedCapitalEnvelope: - wrapper: dict[str, Any] - body: dict[str, Any] - event_id: str - envelope_id: str - source_id: str - source_sequence: int - nonce: str - signer_key_id: str - venue: str - account_hash: str - strategy_hashes: tuple[str, ...] - passport_hashes: tuple[str, ...] - promotion_hashes: tuple[str, ...] - authorized_instruments: tuple[str, ...] - authorized_mode: str - max_order_risk_cents: int - max_open_risk_cents: int - max_correlated_risk_cents: int - max_daily_loss_cents: int - max_open_orders: int - fencing_generation: int - policy_epoch: int - not_before: datetime - expires_at: datetime - ledger_event_digest: str | None = None - ledger_global_sequence: int | None = None - - -@dataclass(frozen=True) -class VerifiedSignedEnvelope: - """Cryptographically verified DumbMoney wrapper with an active window.""" - - wrapper: dict[str, Any] - body: dict[str, Any] - event_id: str - source_id: str - source_sequence: int - nonce: str - signer_key_id: str - body_schema: str - not_before: datetime - expires_at: datetime - - -@dataclass(frozen=True) -class CapitalVerdict: - allow: bool - reason: str - rejected_by: str | None = None - reservation_id: str | None = None - effective_limits: dict[str, int] | None = None - - -class CapitalLineageResolver(Protocol): - """Authenticate one exact singleton lineage through DumbMoney Core.""" - - def resolve_lineage( - self, - *, - capital: VerifiedCapitalEnvelope, - strategy_hash: str, - passport_hash: str, - promotion_hash: str, - authorized_instrument: str, - expected_binding: Mapping[str, Any] | None = None, - ) -> Any: ... - - -def verify_signed_envelope( - wrapper: Mapping[str, Any], - *, - trusted_public_keys: Mapping[str, bytes | Ed25519PublicKey], - now: datetime | None = None, - expected_body_schema: str | None = None, - max_ttl: timedelta | None = None, - require_active: bool = True, -) -> VerifiedSignedEnvelope: - """Validate a complete DumbMoney signed-envelope wrapper. - - This is the shared authority verifier for capital, kill, and desired-mode - commands. It verifies exact wire shape, canonical hashes, signer binding, - signature, and the active authority window. Body-specific semantics remain - the responsibility of the receiving authority adapter. - """ - value = json.loads(canonical_json(dict(wrapper))) - if value.get("schema") != SIGNED_ENVELOPE_SCHEMA: - raise ValueError("signed envelope schema mismatch") - required_wrapper = { - "schema", - "source_id", - "source_sequence", - "event_id", - "correlation_id", - "causation_id", - "nonce", - "not_before", - "expires_at", - "body_schema", - "body_digest", - "body", - "signature_algorithm", - "signer_key_id", - "signature", - } - if set(value) != required_wrapper: - raise ValueError("signed envelope fields mismatch") - source_id = _require_identifier(value["source_id"], field="source_id") - source_sequence = _require_int( - value["source_sequence"], field="source_sequence", minimum=1 - ) - event_id = _require_sha256(value["event_id"], field="event_id") - _require_identifier(value["correlation_id"], field="correlation_id") - if value["causation_id"] is not None: - _require_sha256(value["causation_id"], field="causation_id") - nonce = _require_identifier(value["nonce"], field="nonce") - wrapper_not_before = _parse_utc(value["not_before"], field="not_before") - wrapper_expires_at = _parse_utc(value["expires_at"], field="expires_at") - body_schema = _require_identifier(value["body_schema"], field="body_schema") - if expected_body_schema is not None and body_schema != expected_body_schema: - raise ValueError("body schema mismatch") - if value["signature_algorithm"] != "Ed25519": - raise ValueError("signature algorithm mismatch") - signer_key_id = _require_sha256(value["signer_key_id"], field="signer_key_id") - body_digest = _require_sha256(value["body_digest"], field="body_digest") - body = value["body"] - if not isinstance(body, dict): - raise ValueError("signed envelope body must be an object") - if body.get("schema") != body_schema: - raise ValueError("signed envelope body schema mismatch") - if sha256_json(body) != body_digest: - raise ValueError("signed envelope body digest mismatch") - - event_material = { - key: item - for key, item in value.items() - if key not in {"event_id", "signature"} - } - if sha256_json(event_material) != event_id: - raise ValueError("signed envelope event id mismatch") - - key_material = trusted_public_keys.get(signer_key_id) - if key_material is None: - raise ValueError("signer key is not trusted") - raw_public_key = _public_key_bytes(key_material) - if hashlib.sha256(raw_public_key).hexdigest() != signer_key_id: - raise ValueError("signer key id does not match public key") - signature = _decode_base64url_no_padding( - value["signature"], field="signature" - ) - if len(signature) != 64: - raise ValueError("signed envelope signature must be 64 bytes") - signed_material = {key: item for key, item in value.items() if key != "signature"} - try: - Ed25519PublicKey.from_public_bytes(raw_public_key).verify( - signature, - canonical_json(signed_material).encode("utf-8"), - ) - except (InvalidSignature, ValueError) as exc: - raise ValueError("signed envelope signature invalid") from exc - - if wrapper_expires_at <= wrapper_not_before: - raise ValueError("signed envelope authority window is invalid") - if max_ttl is not None and wrapper_expires_at - wrapper_not_before > max_ttl: - raise ValueError("signed envelope authority window exceeds maximum") - if require_active: - current = now or _utc_now() - if current.tzinfo is None or current.utcoffset() is None: - raise ValueError("verification clock must be timezone-aware") - current = current.astimezone(timezone.utc) - if current < wrapper_not_before: - raise ValueError("signed envelope is not active yet") - if current >= wrapper_expires_at: - raise ValueError("signed envelope expired") - - return VerifiedSignedEnvelope( - wrapper=value, - body=body, - event_id=event_id, - source_id=source_id, - source_sequence=source_sequence, - nonce=nonce, - signer_key_id=signer_key_id, - body_schema=body_schema, - not_before=wrapper_not_before, - expires_at=wrapper_expires_at, - ) - - -def verify_signed_capital_envelope( - wrapper: Mapping[str, Any], - *, - trusted_public_keys: Mapping[str, bytes | Ed25519PublicKey], - expected_venue: str, - expected_account_hash: str, - now: datetime | None = None, - max_ttl: timedelta = timedelta(minutes=5), - require_active: bool = True, -) -> VerifiedCapitalEnvelope: - """Validate the complete DumbMoney wrapper and capital body.""" - signed = verify_signed_envelope( - wrapper, - trusted_public_keys=trusted_public_keys, - now=now, - expected_body_schema=CAPITAL_ENVELOPE_SCHEMA, - max_ttl=max_ttl, - require_active=require_active, - ) - value = signed.wrapper - body = signed.body - required_body = { - "schema", - "envelope_id", - "mandate_id", - "venue", - "account_hash", - "strategy_hashes", - "passport_hashes", - "promotion_hashes", - "authorized_instruments", - "authorized_mode", - "max_order_risk_cents", - "max_open_risk_cents", - "max_correlated_risk_cents", - "max_daily_loss_cents", - "max_open_orders", - "fencing_generation", - "policy_epoch", - "not_before", - "expires_at", - } - if set(body) != required_body: - raise ValueError("capital envelope fields mismatch") - - envelope_id = _require_sha256(body["envelope_id"], field="envelope_id") - _require_sha256(body["mandate_id"], field="mandate_id") - venue = _require_text(body["venue"], field="venue") - if venue not in {"dummy_kalshi", "dopey_robinhood"}: - raise ValueError("capital envelope venue is unsupported") - if venue != expected_venue: - raise ValueError("capital envelope venue mismatch") - account_hash = _require_sha256(body["account_hash"], field="account_hash") - if account_hash != _require_sha256( - expected_account_hash, field="expected_account_hash" - ): - raise ValueError("capital envelope account mismatch") - strategy_hashes = _require_hashes(body["strategy_hashes"], field="strategy_hashes") - passport_hashes = _require_hashes(body["passport_hashes"], field="passport_hashes") - promotion_hashes = _require_hashes( - body["promotion_hashes"], field="promotion_hashes" - ) - if not ( - len(strategy_hashes) == len(passport_hashes) == len(promotion_hashes) - ): - raise ValueError( - "strategy, passport, and promotion hash counts must match" - ) - if len(strategy_hashes) != 1: - raise ValueError( - "capital envelopes authorize exactly one " - "strategy/passport/promotion tuple" - ) - authorized_instruments = _require_identifiers( - body["authorized_instruments"], - field="authorized_instruments", - ) - expected_prefixes = { - "dummy_kalshi": ("event_contract:",), - "dopey_robinhood": ("equity:", "option:"), - }[venue] - if any( - not item.startswith(expected_prefixes) - or item.endswith(":") - or "*" in item - for item in authorized_instruments - ): - raise ValueError("authorized instrument is invalid for venue") - authorized_mode = _require_text(body["authorized_mode"], field="authorized_mode") - if authorized_mode != "LIVE": - raise ValueError("authorized_mode must be LIVE") - max_order = _require_int( - body["max_order_risk_cents"], field="max_order_risk_cents", minimum=1 - ) - max_open = _require_int( - body["max_open_risk_cents"], field="max_open_risk_cents", minimum=1 - ) - max_correlated = _require_int( - body["max_correlated_risk_cents"], - field="max_correlated_risk_cents", - minimum=1, - ) - max_daily_loss = _require_int( - body["max_daily_loss_cents"], field="max_daily_loss_cents", minimum=1 - ) - max_open_orders = _require_int( - body["max_open_orders"], field="max_open_orders", minimum=1 - ) - if not max_order <= max_correlated <= max_open: - raise ValueError("capital envelope limits are internally inconsistent") - fencing_generation = _require_int( - body["fencing_generation"], field="fencing_generation", minimum=1 - ) - policy_epoch = _require_int( - body["policy_epoch"], field="policy_epoch", minimum=1 - ) - body_not_before = _parse_utc(body["not_before"], field="body.not_before") - body_expires_at = _parse_utc(body["expires_at"], field="body.expires_at") - if ( - body_not_before != signed.not_before - or body_expires_at != signed.expires_at - ): - raise ValueError("wrapper and body authority windows differ") - - return VerifiedCapitalEnvelope( - wrapper=value, - body=body, - event_id=signed.event_id, - envelope_id=envelope_id, - source_id=signed.source_id, - source_sequence=signed.source_sequence, - nonce=signed.nonce, - signer_key_id=signed.signer_key_id, - venue=venue, - account_hash=account_hash, - strategy_hashes=strategy_hashes, - passport_hashes=passport_hashes, - promotion_hashes=promotion_hashes, - authorized_instruments=authorized_instruments, - authorized_mode=authorized_mode, - max_order_risk_cents=max_order, - max_open_risk_cents=max_open, - max_correlated_risk_cents=max_correlated, - max_daily_loss_cents=max_daily_loss, - max_open_orders=max_open_orders, - fencing_generation=fencing_generation, - policy_epoch=policy_epoch, - not_before=body_not_before, - expires_at=body_expires_at, - ) - - -def flat_book_receipt( - *, - receipt_id: str, - venue: str, - account_hash: str, - observed_at: str, - broker_snapshot_sha256: str, -) -> dict[str, Any]: - return { - "schema": FLAT_BOOTSTRAP_SCHEMA, - "receipt_id": _require_text(receipt_id, field="receipt_id"), - "venue": _require_text(venue, field="venue"), - "account_hash": _require_sha256(account_hash, field="account_hash"), - "observed_at": observed_at, - "broker_snapshot_sha256": _require_sha256( - broker_snapshot_sha256, field="broker_snapshot_sha256" - ), - "flat_book_observed": True, - "total_exposure_cents": 0, - "open_order_count": 0, - "market_exposure_cents": {}, - "correlated_exposure_cents": {}, - } - - -def inherited_exposure_receipt( - *, - receipt_id: str, - venue: str, - account_hash: str, - observed_at: str, - broker_snapshot_sha256: str, - total_exposure_cents: int, - open_order_count: int, - market_exposure_cents: Mapping[str, int], - correlated_exposure_cents: Mapping[str, int], -) -> dict[str, Any]: - total = _require_int( - total_exposure_cents, field="total_exposure_cents", minimum=0 - ) - orders = _require_int(open_order_count, field="open_order_count", minimum=0) - markets = { - _require_text(str(key), field="market_exposure_key"): _require_int( - item, field="market_exposure_cents", minimum=0 - ) - for key, item in market_exposure_cents.items() - } - correlated = { - _require_text(str(key), field="correlated_exposure_key"): _require_int( - item, field="correlated_exposure_cents", minimum=0 - ) - for key, item in correlated_exposure_cents.items() - } - if total == 0 and orders == 0: - raise ValueError("inherited exposure receipt cannot represent a flat book") - if sum(markets.values()) > total or max(correlated.values(), default=0) > total: - raise ValueError("inherited exposure breakdown exceeds total exposure") - return { - "schema": INHERITED_BOOTSTRAP_SCHEMA, - "receipt_id": _require_text(receipt_id, field="receipt_id"), - "venue": _require_text(venue, field="venue"), - "account_hash": _require_sha256(account_hash, field="account_hash"), - "observed_at": observed_at, - "broker_snapshot_sha256": _require_sha256( - broker_snapshot_sha256, field="broker_snapshot_sha256" - ), - "flat_book_observed": False, - "total_exposure_cents": total, - "open_order_count": orders, - "market_exposure_cents": markets, - "correlated_exposure_cents": correlated, - } - - -class CapitalEnvelopeAdapter: - """Validate grants and durably reserve only bounded additional risk.""" - - def __init__( - self, - *, - journal: AppendOnlyOperationalJournal, - trusted_public_keys: Mapping[str, bytes | Ed25519PublicKey], - expected_venue: str, - expected_account_hash: str, - lineage_resolver: CapitalLineageResolver, - trusted_broker_witness_public_keys: ( - Mapping[str, bytes | Ed25519PublicKey] | None - ) = None, - expected_subaccount_number: int = 0, - now_fn: Callable[[], datetime] | None = None, - max_envelope_ttl: timedelta = timedelta(minutes=5), - max_bootstrap_age: timedelta = timedelta(minutes=5), - ) -> None: - self.journal = journal - self.trusted_public_keys = dict(trusted_public_keys) - self.trusted_broker_witness_public_keys = dict( - trusted_broker_witness_public_keys or {} - ) - self.expected_venue = expected_venue - self.expected_account_hash = _require_sha256( - expected_account_hash, field="expected_account_hash" - ) - if ( - isinstance(expected_subaccount_number, bool) - or not isinstance(expected_subaccount_number, int) - or expected_subaccount_number != 0 - ): - raise ValueError( - "expected_subaccount_number must be 0 until end-to-end " - "subaccount routing is sealed" - ) - self.expected_subaccount_number = expected_subaccount_number - if not hasattr(lineage_resolver, "resolve_lineage") or not callable( - lineage_resolver.resolve_lineage - ): - raise TypeError("a Core authority lineage resolver is required") - self.lineage_resolver = lineage_resolver - self._now_fn = now_fn or _utc_now - self.max_envelope_ttl = max_envelope_ttl - self.max_bootstrap_age = max_bootstrap_age - - def _events(self, kind: str | None = None) -> tuple[dict[str, Any], ...]: - if not self.journal.healthy: - raise OperationalJournalError("capital journal is unhealthy") - return tuple( - dict(row) for row in self.journal.events(kind=kind) - ) - - def accept_signed_envelope( - self, - wrapper: Mapping[str, Any], - *, - ledger_event_digest: str | None = None, - ledger_global_sequence: int | None = None, - ) -> VerifiedCapitalEnvelope: - verified = verify_signed_capital_envelope( - wrapper, - trusted_public_keys=self.trusted_public_keys, - expected_venue=self.expected_venue, - expected_account_hash=self.expected_account_hash, - now=self._now_fn(), - max_ttl=self.max_envelope_ttl, - ) - if (ledger_event_digest is None) != (ledger_global_sequence is None): - raise ValueError( - "capital ledger digest and global sequence must be supplied together" - ) - if ledger_event_digest is not None: - verified = replace( - verified, - ledger_event_digest=_require_sha256( - ledger_event_digest, - field="capital ledger_event_digest", - ), - ledger_global_sequence=_require_int( - ledger_global_sequence, - field="capital ledger_global_sequence", - minimum=1, - ), - ) - payload = { - "event_id": verified.event_id, - "envelope_id": verified.envelope_id, - "source_id": verified.source_id, - "source_sequence": verified.source_sequence, - "nonce": verified.nonce, - "fencing_generation": verified.fencing_generation, - "ledger_event_digest": verified.ledger_event_digest, - "ledger_global_sequence": verified.ledger_global_sequence, - "wrapper": verified.wrapper, - } - - def validate_existing(rows: tuple[dict[str, Any], ...]) -> None: - accepted = [ - row - for row in rows - if row.get("kind") == "capital.envelope.accepted" - ] - seen_nonce = { - str(row["payload"].get("nonce")) - for row in accepted - } - if verified.nonce in seen_nonce: - raise ValueError("capital envelope nonce replay") - source_rows = [ - row - for row in accepted - if row["payload"].get("source_id") == verified.source_id - ] - if source_rows: - highest_sequence = max( - int(row["payload"]["source_sequence"]) - for row in source_rows - ) - if verified.source_sequence <= highest_sequence: - raise ValueError("capital envelope source sequence replay") - highest_fence = max( - ( - int(row["payload"]["fencing_generation"]) - for row in accepted - ), - default=0, - ) - if ( - highest_fence - and verified.fencing_generation <= highest_fence - ): - raise ValueError( - "capital envelope fencing generation is not strictly increasing" - ) - highest_policy_epoch = max( - ( - int(row["payload"]["wrapper"]["body"]["policy_epoch"]) - for row in accepted - ), - default=0, - ) - if verified.policy_epoch < highest_policy_epoch: - raise ValueError("capital envelope policy epoch regressed") - - self.journal.append( - "capital.envelope.accepted", - payload, - outbox_id=f"capital-envelope:{verified.event_id}", - validate_existing=validate_existing, - ) - return verified - - def record_broker_bootstrap( - self, receipt: Mapping[str, Any] - ) -> dict[str, Any]: - value = json.loads(canonical_json(dict(receipt))) - schema = value.get("schema") - if schema not in {FLAT_BOOTSTRAP_SCHEMA, INHERITED_BOOTSTRAP_SCHEMA}: - raise ValueError("broker bootstrap receipt schema mismatch") - if value.get("venue") != self.expected_venue: - raise ValueError("broker bootstrap venue mismatch") - if value.get("account_hash") != self.expected_account_hash: - raise ValueError("broker bootstrap account mismatch") - _require_text(value.get("receipt_id"), field="receipt_id") - observed = _parse_utc(value.get("observed_at"), field="observed_at") - now = self._now_fn().astimezone(timezone.utc) - if observed > now + timedelta(seconds=5): - raise ValueError("broker bootstrap receipt is from the future") - if now - observed > self.max_bootstrap_age: - raise ValueError("broker bootstrap receipt is stale") - _require_sha256( - value.get("broker_snapshot_sha256"), field="broker_snapshot_sha256" - ) - total = _require_int( - value.get("total_exposure_cents"), - field="total_exposure_cents", - minimum=0, - ) - orders = _require_int( - value.get("open_order_count"), field="open_order_count", minimum=0 - ) - markets = value.get("market_exposure_cents") - correlated = value.get("correlated_exposure_cents") - if not isinstance(markets, dict) or not isinstance(correlated, dict): - raise ValueError("broker bootstrap exposure maps are required") - for item in (*markets.values(), *correlated.values()): - _require_int(item, field="bootstrap_exposure_cents", minimum=0) - if schema == FLAT_BOOTSTRAP_SCHEMA: - if ( - value.get("flat_book_observed") is not True - or total != 0 - or orders != 0 - or markets - or correlated - ): - raise ValueError("flat bootstrap receipt contains exposure") - elif ( - value.get("flat_book_observed") is not False - or (total == 0 and orders == 0) - ): - raise ValueError("inherited bootstrap receipt lacks exposure") - def validate_existing(rows: tuple[dict[str, Any], ...]) -> None: - prior_rows = [ - row - for row in rows - if row.get("kind") == "broker.bootstrap.recorded" - ] - if prior_rows: - previous_observed = _parse_utc( - prior_rows[-1]["payload"]["observed_at"], - field="previous.observed_at", - ) - if observed <= previous_observed: - raise ValueError( - "broker bootstrap observations must be strictly increasing" - ) - - event = self.journal.append( - "broker.bootstrap.recorded", - value, - outbox_id=f"broker-bootstrap:{value['receipt_id']}", - validate_existing=validate_existing, - validate_existing_latest_kinds=("broker.bootstrap.recorded",), - ) - return dict(event) - - def _latest_bootstrap(self) -> dict[str, Any] | None: - rows = self._events("broker.bootstrap.recorded") - return dict(rows[-1]["payload"]) if rows else None - - def _accepted_envelopes(self) -> list[VerifiedCapitalEnvelope]: - verified: list[VerifiedCapitalEnvelope] = [] - for row in self._events("capital.envelope.accepted"): - try: - accepted = verify_signed_capital_envelope( - row["payload"]["wrapper"], - trusted_public_keys=self.trusted_public_keys, - expected_venue=self.expected_venue, - expected_account_hash=self.expected_account_hash, - now=self._now_fn(), - max_ttl=self.max_envelope_ttl, - ) - ledger_digest = row["payload"].get("ledger_event_digest") - ledger_sequence = row["payload"].get("ledger_global_sequence") - if ledger_digest is not None or ledger_sequence is not None: - accepted = replace( - accepted, - ledger_event_digest=_require_sha256( - ledger_digest, - field="capital ledger_event_digest", - ), - ledger_global_sequence=_require_int( - ledger_sequence, - field="capital ledger_global_sequence", - minimum=1, - ), - ) - verified.append( - accepted - ) - except ValueError: - # Expired grants are normal history and are simply inactive. - continue - return verified - - def _maximum_accepted_fence(self) -> int: - """Return the monotonic high-water fence, including expired grants.""" - return max( - ( - int(row["payload"]["fencing_generation"]) - for row in self._events("capital.envelope.accepted") - ), - default=0, - ) - - def _active_reservations(self) -> list[dict[str, Any]]: - reservations = { - str(row["payload"]["reservation_id"]): dict(row["payload"]) - for row in self._events("capital.reservation.created") - } - released = { - str(row["payload"]["reservation_id"]) - for row in self._events("capital.reservation.released") - } - return [ - value for key, value in reservations.items() if key not in released - ] - - def _active_position_exposures(self) -> list[dict[str, Any]]: - positions = { - str(row["payload"]["position_exposure_id"]): dict( - row["payload"] - ) - for row in self._events("capital.position.exposure.recorded") - } - released = { - str(row["payload"]["position_exposure_id"]) - for row in self._events("capital.position.exposure.released") - } - return [ - value for key, value in positions.items() if key not in released - ] - - @staticmethod - def _fee_inclusive_order_risk( - request: Any, - ) -> tuple[int, int, int]: - size = _require_int( - int(request.size), - field="order_size", - minimum=1, - ) - price = _require_int( - int(request.price_cents), - field="order_price_cents", - minimum=1, - ) - if price > 100: - raise ValueError("order_price_cents must be <= 100") - notional = size * price - # Reserve at the general taker schedule even for post-only makers. - # This remains conservative if maker classification or the embedded - # maker-series schedule changes before a fill is reconciled. - fee = kalshi_taker_fee_cents( - price, - size, - str(request.market_ticker), - ) - return notional, fee, notional + fee - - def _cancel_only(self) -> bool: - rows = self._events("authority.cancel_only") - return bool(rows) - - def binding_for( - self, - *, - strategy_hash: str, - passport_hash: str, - authorized_instrument: str, - promotion_hash: str | None = None, - ) -> dict[str, Any]: - strategy = _require_sha256(strategy_hash, field="strategy_hash") - passport = _require_sha256(passport_hash, field="passport_hash") - instrument = _require_identifier( - authorized_instrument, - field="authorized_instrument", - ) - promotion = ( - _require_sha256(promotion_hash, field="promotion_hash") - if promotion_hash is not None - else None - ) - eligible = [ - envelope - for envelope in self._accepted_envelopes() - if envelope.authorized_mode == "LIVE" - and envelope.fencing_generation == self._maximum_accepted_fence() - and strategy in envelope.strategy_hashes - and passport in envelope.passport_hashes - and instrument in envelope.authorized_instruments - and ( - promotion in envelope.promotion_hashes - if promotion is not None - else len(envelope.promotion_hashes) == 1 - ) - ] - if not eligible: - raise ValueError("no active capital envelope covers request lineage") - selected = max( - eligible, - key=lambda item: ( - item.fencing_generation, - item.source_sequence, - item.expires_at, - ), - ) - selected_promotion = ( - promotion - if promotion is not None - else selected.promotion_hashes[0] - ) - binding = self.lineage_resolver.resolve_lineage( - capital=selected, - strategy_hash=strategy, - passport_hash=passport, - promotion_hash=selected_promotion, - authorized_instrument=instrument, - ) - evidence = json.loads(canonical_json(binding.evidence())) - # Resolution pages contain a fresh request nonce, so retain only the - # stable, cryptographically authenticated identity for the sink's - # independent revalidation. - evidence.pop("passport_resolution_sha256", None) - evidence.pop("promotion_resolution_sha256", None) - lineage_id = sha256_json(evidence) - self.journal.append( - "capital.lineage.verified", - { - "lineage_id": lineage_id, - "binding": evidence, - }, - outbox_id=f"capital-lineage:{lineage_id}", - ) - return { - "capital_envelope_id": selected.envelope_id, - "capital_strategy_hash": strategy, - "capital_passport_hash": passport, - "capital_promotion_hash": selected_promotion, - "capital_fencing_generation": selected.fencing_generation, - } - - @staticmethod - def _correlation_key(market_ticker: str) -> str: - return market_ticker.split("-", 1)[0].upper() - - @staticmethod - def _request_order_terms(request: Any) -> dict[str, Any]: - return { - "proposal_id": str(request.proposal_id), - "market_ticker": str(request.market_ticker), - "contract_ticker": str(request.contract_ticker), - "side": str(request.side), - "size": int(request.size), - "price_cents": int(request.price_cents), - "expiration_ts": ( - int(request.expiration_ts) - if getattr(request, "expiration_ts", None) is not None - else None - ), - "liquidity_role": str( - getattr(request, "liquidity_role", "maker") or "maker" - ), - "capital_envelope_id": str( - getattr(request, "capital_envelope_id", "") or "" - ), - "capital_strategy_hash": str( - getattr(request, "capital_strategy_hash", "") or "" - ), - "capital_passport_hash": str( - getattr(request, "capital_passport_hash", "") or "" - ), - "capital_promotion_hash": str( - getattr(request, "capital_promotion_hash", "") or "" - ), - "capital_fencing_generation": int( - getattr(request, "capital_fencing_generation") - ), - } - - @staticmethod - def _expected_broker_order(request: Any) -> dict[str, Any]: - """Reconstruct the exact order payload authorized by the request. - - A dispatch claim is a broker-send capability, so hashing an arbitrary - caller-supplied mapping is insufficient. Keep this fail-closed mirror - of ``LiveBrokerFirewall._build_order`` until the broker wire contract - is migrated as one atomic change. - """ - side = str(request.side) - if side not in {"yes", "no"}: - raise ValueError("dispatch request side is invalid") - count = _require_int(request.size, field="dispatch count", minimum=1) - price = _require_int( - request.price_cents, - field="dispatch price_cents", - minimum=1, - ) - if price > 99: - raise ValueError("dispatch price_cents must be <= 99") - yes_price_cents = price if side == "yes" else 100 - price - maker = ( - str(getattr(request, "liquidity_role", "maker") or "maker") - == "maker" - ) - expected: dict[str, Any] = { - "ticker": _require_identifier( - request.contract_ticker, - field="dispatch ticker", - ), - "client_order_id": _require_identifier( - request.proposal_id, - field="dispatch client_order_id", - ), - "side": "bid" if side == "yes" else "ask", - "count": f"{count}.00", - "price": f"0.{yes_price_cents:02d}00", - "time_in_force": ( - "good_till_canceled" if maker else "fill_or_kill" - ), - "self_trade_prevention_type": "taker_at_cross", - "post_only": maker, - "cancel_order_on_pause": True, - "reduce_only": False, - "subaccount": 0, - "exchange_index": 0, - } - expiration = getattr(request, "expiration_ts", None) - if maker: - if expiration is None: - raise ValueError( - "dispatch maker order lacks exchange-enforced expiration" - ) - expected["expiration_time"] = _require_int( - expiration, - field="dispatch expiration_time", - minimum=1, - ) - return expected - - def _resolve_envelope_for_request(self, request: Any) -> VerifiedCapitalEnvelope: - envelope_id = str(getattr(request, "capital_envelope_id", "") or "") - strategy_hash = str(getattr(request, "capital_strategy_hash", "") or "") - passport_hash = str(getattr(request, "capital_passport_hash", "") or "") - promotion_hash = str(getattr(request, "capital_promotion_hash", "") or "") - contract_ticker = _require_identifier( - str(getattr(request, "contract_ticker", "") or ""), - field="contract_ticker", - ) - authorized_instrument = f"event_contract:{contract_ticker}" - try: - fence = int(getattr(request, "capital_fencing_generation")) - except (TypeError, ValueError): - raise ValueError("capital fencing generation missing") from None - candidates = [ - envelope - for envelope in self._accepted_envelopes() - if envelope.envelope_id == envelope_id - and envelope.fencing_generation == fence - ] - if not candidates: - raise ValueError("capital envelope is missing, expired, or fenced") - envelope = max(candidates, key=lambda item: item.source_sequence) - if envelope.authorized_mode != "LIVE": - raise ValueError("capital envelope does not authorize LIVE mode") - if strategy_hash not in envelope.strategy_hashes: - raise ValueError("capital strategy hash mismatch") - if passport_hash not in envelope.passport_hashes: - raise ValueError("capital passport hash mismatch") - if promotion_hash not in envelope.promotion_hashes: - raise ValueError("capital promotion hash mismatch") - if authorized_instrument not in envelope.authorized_instruments: - raise ValueError("capital instrument is not authorized") - highest_fence = self._maximum_accepted_fence() - if fence != highest_fence: - raise ValueError("capital envelope fencing generation is stale") - prior_bindings = [ - row["payload"]["binding"] - for row in self._events("capital.lineage.verified") - if isinstance(row.get("payload", {}).get("binding"), dict) - ] - expected_binding = next( - ( - binding - for binding in reversed(prior_bindings) - if binding.get("capital_envelope_id") == envelope.envelope_id - and binding.get("capital_event_id") == envelope.event_id - and binding.get("capital_body_digest") - == sha256_json(envelope.body) - and binding.get("capital_fencing_generation") == fence - and binding.get("policy_epoch") == envelope.policy_epoch - and binding.get("strategy_hash") == strategy_hash - and binding.get("passport_hash") == passport_hash - and binding.get("promotion_hash") == promotion_hash - and binding.get("authorized_instrument") - == authorized_instrument - ), - None, - ) - binding = self.lineage_resolver.resolve_lineage( - capital=envelope, - strategy_hash=strategy_hash, - passport_hash=passport_hash, - promotion_hash=promotion_hash, - authorized_instrument=authorized_instrument, - expected_binding=expected_binding, - ) - if expected_binding is None: - # A manually assembled request cannot self-assert lineage. The - # sink may establish the missing durable receipt only by resolving - # both original signed contracts through Core immediately now. - evidence = json.loads(canonical_json(binding.evidence())) - evidence.pop("passport_resolution_sha256", None) - evidence.pop("promotion_resolution_sha256", None) - lineage_id = sha256_json(evidence) - self.journal.append( - "capital.lineage.verified", - { - "lineage_id": lineage_id, - "binding": evidence, - }, - outbox_id=f"capital-lineage:{lineage_id}", - ) - return envelope - - def _verdict( - self, - request: Any, - *, - current_daily_loss_cents: int, - current_local_total_exposure_cents: int = 0, - current_local_correlated_exposure_cents: int = 0, - current_local_open_orders: int = 0, - current_request_locally_reserved: bool = False, - ) -> tuple[CapitalVerdict, VerifiedCapitalEnvelope | None, dict[str, Any] | None]: - if self._cancel_only(): - return ( - CapitalVerdict( - False, - "DumbMoney adapter is in cancel-only degraded mode", - "capital_cancel_only", - ), - None, - None, - ) - bootstrap = self._latest_bootstrap() - if bootstrap is None: - return ( - CapitalVerdict( - False, - "Fresh broker bootstrap receipt required; local absence is not flat", - "capital_broker_bootstrap", - ), - None, - None, - ) - try: - observed = _parse_utc(bootstrap["observed_at"], field="observed_at") - if self._now_fn().astimezone(timezone.utc) - observed > self.max_bootstrap_age: - raise ValueError("broker bootstrap receipt is stale") - envelope = self._resolve_envelope_for_request(request) - _, _, order_risk = self._fee_inclusive_order_risk(request) - daily_loss = _require_int( - current_daily_loss_cents, - field="current_daily_loss_cents", - minimum=0, - ) - local_total = _require_int( - current_local_total_exposure_cents, - field="current_local_total_exposure_cents", - minimum=0, - ) - local_correlated = _require_int( - current_local_correlated_exposure_cents, - field="current_local_correlated_exposure_cents", - minimum=0, - ) - local_open_orders = _require_int( - current_local_open_orders, - field="current_local_open_orders", - minimum=0, - ) - except Exception as exc: - return ( - CapitalVerdict(False, str(exc), "capital_envelope"), - None, - bootstrap, - ) - active = self._active_reservations() - active_positions = self._active_position_exposures() - proposal_id = str(request.proposal_id) - terminal_witness = next( - ( - row["payload"] - for row in self._events( - "capital.terminal_reconciliation.witnessed" - ) - if row["payload"].get("proposal_id") == proposal_id - ), - None, - ) - if terminal_witness is not None: - return ( - CapitalVerdict( - False, - "proposal id has a broker terminal witness and cannot be reused", - "capital_idempotency", - ), - envelope, - bootstrap, - ) - existing = next( - ( - item - for item in active - if item.get("proposal_id") == proposal_id - ), - None, - ) - if existing is not None: - request_terms_sha256 = sha256_json( - self._request_order_terms(request) - ) - matches = ( - existing.get("envelope_id") == envelope.envelope_id - and existing.get("market_ticker") == request.market_ticker - and existing.get("contract_ticker") - == request.contract_ticker - and existing.get("side") == request.side - and int(existing.get("size", -1)) == int(request.size) - and int(existing.get("price_cents", -1)) == int(request.price_cents) - and existing.get("account_hash") == envelope.account_hash - and existing.get("venue") == envelope.venue - and existing.get("strategy_hash") - == str(request.capital_strategy_hash) - and existing.get("passport_hash") - == str(request.capital_passport_hash) - and existing.get("promotion_hash") - == str(request.capital_promotion_hash) - and existing.get("order_terms_sha256") - == request_terms_sha256 - ) - if not matches: - return ( - CapitalVerdict( - False, - "proposal id already reserved for different order terms", - "capital_idempotency", - ), - envelope, - bootstrap, - ) - else: - prior_terminal = next( - ( - row["payload"] - for row in self._events("capital.reservation.created") - if row["payload"].get("proposal_id") == proposal_id - ), - None, - ) - if prior_terminal is not None: - return ( - CapitalVerdict( - False, - "proposal id has a terminal capital reservation and cannot be reused", - "capital_idempotency", - ), - envelope, - bootstrap, - ) - inherited_total = int(bootstrap["total_exposure_cents"]) - inherited_orders = int(bootstrap["open_order_count"]) - reserved_total = sum(int(item["risk_cents"]) for item in active) - position_total = sum( - int(item["risk_cents"]) for item in active_positions - ) - correlation_key = self._correlation_key(str(request.market_ticker)) - inherited_correlated = int( - bootstrap["correlated_exposure_cents"].get(correlation_key, 0) - ) - reserved_correlated = sum( - int(item["risk_cents"]) - for item in active - if item.get("correlation_key") == correlation_key - ) - position_correlated = sum( - int(item["risk_cents"]) - for item in active_positions - if item.get("correlation_key") == correlation_key - ) - adjusted_local_total = local_total - adjusted_local_correlated = local_correlated - adjusted_local_orders = local_open_orders - if existing is not None and current_request_locally_reserved: - existing_risk = int(existing["risk_cents"]) - if ( - adjusted_local_total < existing_risk - or adjusted_local_correlated < existing_risk - or adjusted_local_orders < 1 - ): - return ( - CapitalVerdict( - False, - "local reservation witness is inconsistent", - "capital_local_reservation", - ), - envelope, - bootstrap, - ) - # This is the only overlap we can prove: the exact proposal is - # present in both Dummy's local submission ledger and this - # adapter's reservation journal. Preserve conservative addition - # for every other exposure. - adjusted_local_total -= existing_risk - adjusted_local_correlated -= existing_risk - adjusted_local_orders -= 1 - limits = { - "max_order_risk_cents": envelope.max_order_risk_cents, - "max_open_risk_cents": envelope.max_open_risk_cents, - "max_correlated_risk_cents": envelope.max_correlated_risk_cents, - "max_daily_loss_cents": envelope.max_daily_loss_cents, - "max_open_orders": envelope.max_open_orders, - } - # These three books have no signed overlap proof. Treat them as - # disjoint until reconciliation supplies one: using max() can mask a - # post-bootstrap fill behind a larger inherited baseline after its - # reservation is released. Conservative addition may double count an - # order represented in both local and adapter state, but never grants - # capital against exposure whose overlap is merely assumed. - effective_open_risk = ( - inherited_total - + reserved_total - + position_total - + adjusted_local_total - ) - effective_correlated_risk = ( - inherited_correlated - + reserved_correlated - + position_correlated - + adjusted_local_correlated - ) - effective_open_orders = ( - inherited_orders + len(active) + adjusted_local_orders - ) - if order_risk > envelope.max_order_risk_cents: - reason = "DumbMoney maximum order risk exceeded" - elif ( - effective_open_risk - + (0 if existing is not None else order_risk) - > envelope.max_open_risk_cents - ): - reason = "DumbMoney maximum open risk exceeded" - elif ( - effective_correlated_risk - + (0 if existing is not None else order_risk) - > envelope.max_correlated_risk_cents - ): - reason = "DumbMoney maximum correlated risk exceeded" - elif ( - order_risk - > envelope.max_daily_loss_cents - daily_loss - ): - reason = "DumbMoney daily loss capacity exceeded" - elif ( - effective_open_orders - + (0 if existing is not None else 1) - > envelope.max_open_orders - ): - reason = "DumbMoney maximum open orders reached" - else: - return ( - CapitalVerdict( - True, - ( - "Existing durable DumbMoney reservation verified" - if existing is not None - else "Signed DumbMoney capital grant bounds verified" - ), - reservation_id=( - str(existing["reservation_id"]) - if existing is not None - else None - ), - effective_limits=limits, - ), - envelope, - bootstrap, - ) - return ( - CapitalVerdict( - False, - reason, - "capital_limits", - effective_limits=limits, - ), - envelope, - bootstrap, - ) - - def evaluate_request( - self, - request: Any, - *, - current_daily_loss_cents: int, - current_local_total_exposure_cents: int = 0, - current_local_correlated_exposure_cents: int = 0, - current_local_open_orders: int = 0, - current_request_locally_reserved: bool = False, - ) -> CapitalVerdict: - verdict, _, _ = self._verdict( - request, - current_daily_loss_cents=current_daily_loss_cents, - current_local_total_exposure_cents=( - current_local_total_exposure_cents - ), - current_local_correlated_exposure_cents=( - current_local_correlated_exposure_cents - ), - current_local_open_orders=current_local_open_orders, - current_request_locally_reserved=( - current_request_locally_reserved - ), - ) - return verdict - - def reserve_request( - self, - request: Any, - *, - current_daily_loss_cents: int, - current_local_total_exposure_cents: int = 0, - current_local_correlated_exposure_cents: int = 0, - current_local_open_orders: int = 0, - ) -> CapitalVerdict: - verdict, envelope, bootstrap = self._verdict( - request, - current_daily_loss_cents=current_daily_loss_cents, - current_local_total_exposure_cents=( - current_local_total_exposure_cents - ), - current_local_correlated_exposure_cents=( - current_local_correlated_exposure_cents - ), - current_local_open_orders=current_local_open_orders, - ) - if ( - not verdict.allow - or envelope is None - or bootstrap is None - or verdict.reservation_id is not None - ): - return verdict - reservation_id = hashlib.sha256( - ( - f"{envelope.envelope_id}|{envelope.fencing_generation}|" - f"{request.proposal_id}" - ).encode("utf-8") - ).hexdigest() - notional_cents, fee_reserve_cents, risk_cents = ( - self._fee_inclusive_order_risk(request) - ) - payload = { - "schema": CAPITAL_RESERVATION_SCHEMA, - "reservation_id": reservation_id, - "proposal_id": str(request.proposal_id), - "envelope_id": envelope.envelope_id, - "fencing_generation": envelope.fencing_generation, - "market_ticker": str(request.market_ticker), - "contract_ticker": str(request.contract_ticker), - "correlation_key": self._correlation_key(str(request.market_ticker)), - "side": str(request.side), - "size": int(request.size), - "price_cents": int(request.price_cents), - "notional_cents": notional_cents, - "fee_reserve_cents": fee_reserve_cents, - "risk_cents": risk_cents, - "venue": envelope.venue, - "account_hash": envelope.account_hash, - "subaccount_number": self.expected_subaccount_number, - "strategy_hash": str(request.capital_strategy_hash), - "passport_hash": str(request.capital_passport_hash), - "promotion_hash": str(request.capital_promotion_hash), - "expiration_ts": ( - int(request.expiration_ts) - if getattr(request, "expiration_ts", None) is not None - else None - ), - "liquidity_role": str( - getattr(request, "liquidity_role", "maker") or "maker" - ), - "order_terms_sha256": sha256_json( - self._request_order_terms(request) - ), - } - daily_loss = _require_int( - current_daily_loss_cents, - field="current_daily_loss_cents", - minimum=0, - ) - local_total = _require_int( - current_local_total_exposure_cents, - field="current_local_total_exposure_cents", - minimum=0, - ) - local_correlated = _require_int( - current_local_correlated_exposure_cents, - field="current_local_correlated_exposure_cents", - minimum=0, - ) - local_open_orders = _require_int( - current_local_open_orders, - field="current_local_open_orders", - minimum=0, - ) - - def validate_existing(rows: tuple[dict[str, Any], ...]) -> None: - if any( - row.get("kind") == "authority.cancel_only" - for row in rows - ): - raise ValueError( - "DumbMoney adapter is in cancel-only degraded mode" - ) - accepted = [ - row - for row in rows - if row.get("kind") == "capital.envelope.accepted" - ] - highest_fence = max( - ( - int(row["payload"]["fencing_generation"]) - for row in accepted - ), - default=0, - ) - if not any( - row["payload"].get("envelope_id") - == envelope.envelope_id - and int(row["payload"]["fencing_generation"]) - == envelope.fencing_generation - for row in accepted - ): - raise ValueError("capital envelope is no longer accepted") - if highest_fence != envelope.fencing_generation: - raise ValueError("capital envelope fencing generation is stale") - now = self._now_fn() - if now.tzinfo is None or now.utcoffset() is None: - raise ValueError("reservation clock must be timezone-aware") - now = now.astimezone(timezone.utc) - if now >= envelope.expires_at: - raise ValueError("capital envelope expired before reservation") - - bootstrap_rows = [ - row - for row in rows - if row.get("kind") == "broker.bootstrap.recorded" - ] - if not bootstrap_rows: - raise ValueError("broker bootstrap receipt disappeared") - latest_bootstrap = bootstrap_rows[-1]["payload"] - observed = _parse_utc( - latest_bootstrap["observed_at"], - field="observed_at", - ) - if now - observed > self.max_bootstrap_age: - raise ValueError("broker bootstrap receipt is stale") - - created = { - str(row["payload"]["reservation_id"]): row["payload"] - for row in rows - if row.get("kind") == "capital.reservation.created" - } - released = { - str(row["payload"]["reservation_id"]) - for row in rows - if row.get("kind") == "capital.reservation.released" - } - if any( - item.get("proposal_id") == payload["proposal_id"] - for item in created.values() - ): - raise ValueError( - "proposal id already has a capital reservation" - ) - active = [ - item - for key, item in created.items() - if key not in released - ] - position_created = { - str(row["payload"]["position_exposure_id"]): row[ - "payload" - ] - for row in rows - if row.get("kind") - == "capital.position.exposure.recorded" - } - position_released = { - str(row["payload"]["position_exposure_id"]) - for row in rows - if row.get("kind") - == "capital.position.exposure.released" - } - active_positions = [ - item - for key, item in position_created.items() - if key not in position_released - ] - risk_value = payload["risk_cents"] - if isinstance(risk_value, bool) or not isinstance(risk_value, int): - raise ValueError("capital reservation risk is invalid") - order_risk = risk_value - inherited_total = int( - latest_bootstrap["total_exposure_cents"] - ) - inherited_orders = int(latest_bootstrap["open_order_count"]) - inherited_correlated = int( - latest_bootstrap["correlated_exposure_cents"].get( - payload["correlation_key"], - 0, - ) - ) - reserved_total = sum( - int(item["risk_cents"]) for item in active - ) - position_total = sum( - int(item["risk_cents"]) for item in active_positions - ) - reserved_correlated = sum( - int(item["risk_cents"]) - for item in active - if item.get("correlation_key") - == payload["correlation_key"] - ) - position_correlated = sum( - int(item["risk_cents"]) - for item in active_positions - if item.get("correlation_key") - == payload["correlation_key"] - ) - effective_open_risk = ( - inherited_total - + reserved_total - + position_total - + local_total - ) - effective_correlated_risk = ( - inherited_correlated - + reserved_correlated - + position_correlated - + local_correlated - ) - effective_open_orders = ( - inherited_orders + len(active) + local_open_orders - ) - if order_risk > envelope.max_order_risk_cents: - raise ValueError("DumbMoney maximum order risk exceeded") - if ( - effective_open_risk + order_risk - > envelope.max_open_risk_cents - ): - raise ValueError("DumbMoney maximum open risk exceeded") - if ( - effective_correlated_risk + order_risk - > envelope.max_correlated_risk_cents - ): - raise ValueError( - "DumbMoney maximum correlated risk exceeded" - ) - if ( - order_risk - > envelope.max_daily_loss_cents - daily_loss - ): - raise ValueError("DumbMoney daily loss capacity exceeded") - if effective_open_orders >= envelope.max_open_orders: - raise ValueError("DumbMoney maximum open orders reached") - - try: - self.journal.append( - "capital.reservation.created", - payload, - outbox_id=f"capital-reservation:{reservation_id}", - validate_existing=validate_existing, - ) - except ValueError as exc: - return CapitalVerdict( - False, - str(exc), - "capital_atomic_reservation", - effective_limits=verdict.effective_limits, - ) - return CapitalVerdict( - True, - "DumbMoney capital reserved durably", - reservation_id=reservation_id, - effective_limits=verdict.effective_limits, - ) - - def _reservation_for_proposal( - self, - proposal_id: str, - ) -> dict[str, Any] | None: - normalized = str(proposal_id).strip() - return next( - ( - dict(row["payload"]) - for row in self._events("capital.reservation.created") - if row["payload"].get("proposal_id") == normalized - ), - None, - ) - - def claim_broker_dispatch( - self, - request: Any, - *, - reservation_id: str, - order: Mapping[str, Any], - claimant_nonce: str, - ) -> dict[str, Any]: - """Acquire the one-shot cross-process broker-dispatch right. - - The deterministic outbox id is intentionally non-idempotent for this - operation: a prior identical claim is still a consumed authority, not - permission to retry a possibly successful broker request. - """ - nonce = _require_sha256( - claimant_nonce, - field="dispatch claimant_nonce", - ) - reservation = self._reservation_for_proposal( - str(request.proposal_id) - ) - if ( - reservation is None - or reservation.get("reservation_id") != reservation_id - ): - raise ValueError( - "dispatch claim lacks the exact capital reservation" - ) - order_value = json.loads(canonical_json(dict(order))) - expected_order = self._expected_broker_order(request) - if canonical_json(order_value) != canonical_json(expected_order): - raise ValueError( - "dispatch order differs from the exact authorized wire payload" - ) - order_digest = sha256_json(order_value) - request_terms = self._request_order_terms(request) - request_terms_digest = sha256_json(request_terms) - if reservation.get("order_terms_sha256") != request_terms_digest: - raise ValueError( - "dispatch request differs from reserved order terms" - ) - payload = { - "schema": CAPITAL_DISPATCH_CLAIM_SCHEMA, - "reservation_id": reservation_id, - "proposal_id": str(request.proposal_id), - "client_order_id": str(order_value.get("client_order_id") or ""), - "venue": self.expected_venue, - "account_hash": self.expected_account_hash, - "subaccount_number": self.expected_subaccount_number, - "envelope_id": reservation["envelope_id"], - "fencing_generation": reservation["fencing_generation"], - "strategy_hash": reservation["strategy_hash"], - "passport_hash": reservation["passport_hash"], - "promotion_hash": reservation["promotion_hash"], - "authorized_instrument": ( - f"event_contract:{request.contract_ticker}" - ), - "request_terms_sha256": request_terms_digest, - "order_sha256": order_digest, - "order": order_value, - "claimant_nonce": nonce, - } - if payload["client_order_id"] != str(request.proposal_id): - raise ValueError( - "dispatch order client_order_id differs from proposal" - ) - - def validate_existing(rows: tuple[dict[str, Any], ...]) -> None: - if any( - row.get("kind") == "authority.cancel_only" - for row in rows - ): - raise ValueError( - "DumbMoney adapter is in cancel-only degraded mode" - ) - created = { - str(row["payload"]["reservation_id"]): row["payload"] - for row in rows - if row.get("kind") == "capital.reservation.created" - } - released = { - str(row["payload"]["reservation_id"]) - for row in rows - if row.get("kind") == "capital.reservation.released" - } - if reservation_id not in created or reservation_id in released: - raise ValueError( - "dispatch capital reservation is not active" - ) - if created[reservation_id] != reservation: - raise ValueError( - "dispatch capital reservation changed" - ) - if any( - row.get("kind") == "capital.dispatch.claimed" - and ( - row["payload"].get("reservation_id") == reservation_id - or row["payload"].get("proposal_id") - == str(request.proposal_id) - ) - for row in rows - ): - raise ValueError( - "broker dispatch was already claimed" - ) - if any( - row.get("kind") - == "capital.terminal_reconciliation.witnessed" - and row["payload"].get("proposal_id") - == str(request.proposal_id) - for row in rows - ): - raise ValueError( - "terminal proposal cannot acquire dispatch" - ) - accepted = [ - row - for row in rows - if row.get("kind") == "capital.envelope.accepted" - ] - accepted_row = next( - ( - row - for row in reversed(accepted) - if row["payload"].get("envelope_id") - == reservation["envelope_id"] - and int(row["payload"]["fencing_generation"]) - == int(reservation["fencing_generation"]) - ), - None, - ) - if accepted_row is None: - raise ValueError( - "dispatch capital envelope is no longer accepted" - ) - highest_fence = max( - ( - int(row["payload"]["fencing_generation"]) - for row in accepted - ), - default=0, - ) - if highest_fence != int(reservation["fencing_generation"]): - raise ValueError( - "dispatch capital fence is stale" - ) - now = self._now_fn() - if now.tzinfo is None or now.utcoffset() is None: - raise ValueError("dispatch clock must be timezone-aware") - now = now.astimezone(timezone.utc) - verified = verify_signed_capital_envelope( - accepted_row["payload"]["wrapper"], - trusted_public_keys=self.trusted_public_keys, - expected_venue=self.expected_venue, - expected_account_hash=self.expected_account_hash, - now=now, - max_ttl=self.max_envelope_ttl, - ) - if ( - verified.envelope_id != reservation["envelope_id"] - or verified.fencing_generation - != int(reservation["fencing_generation"]) - or verified.authorized_mode != "LIVE" - or reservation["strategy_hash"] - not in verified.strategy_hashes - or reservation["passport_hash"] - not in verified.passport_hashes - or reservation["promotion_hash"] - not in verified.promotion_hashes - or payload["authorized_instrument"] - not in verified.authorized_instruments - ): - raise ValueError( - "dispatch capital envelope binding is not active" - ) - bootstrap_rows = [ - row - for row in rows - if row.get("kind") == "broker.bootstrap.recorded" - ] - if not bootstrap_rows: - raise ValueError( - "dispatch requires a broker bootstrap receipt" - ) - observed = _parse_utc( - bootstrap_rows[-1]["payload"]["observed_at"], - field="observed_at", - ) - if now - observed > self.max_bootstrap_age: - raise ValueError( - "broker bootstrap receipt expired before dispatch" - ) - - event = self.journal.append( - "capital.dispatch.claimed", - payload, - outbox_id=f"capital-dispatch:{reservation_id}", - allow_existing_outbox=False, - validate_existing=validate_existing, - ) - return dict(event) - - def pending_reconciliation_reservations( - self, - ) -> tuple[dict[str, Any], ...]: - """Expose conservative active reservations to the read-only sweeper.""" - claims = { - str(row["payload"]["reservation_id"]) - for row in self._events("capital.dispatch.claimed") - } - return tuple( - { - **item, - "dispatch_claimed": ( - str(item["reservation_id"]) in claims - ), - } - for item in self._active_reservations() - ) - - def active_position_exposures( - self, - ) -> tuple[dict[str, Any], ...]: - """Expose unsettled, independently charged capital positions.""" - return tuple(self._active_position_exposures()) - - def _verify_broker_witness( - self, - wrapper: Mapping[str, Any], - *, - expected_schema: str, - ) -> VerifiedSignedEnvelope: - if not self.trusted_broker_witness_public_keys: - raise ValueError( - "trusted broker witness identity is unavailable" - ) - signed = verify_signed_envelope( - wrapper, - trusted_public_keys=( - self.trusted_broker_witness_public_keys - ), - expected_body_schema=expected_schema, - max_ttl=WITNESS_TTL, - require_active=False, - ) - if signed.source_id != BROKER_WITNESS_SOURCE_ID: - raise ValueError("broker witness source identity mismatch") - body = signed.body - if ( - body.get("venue") != self.expected_venue - or body.get("account_hash") != self.expected_account_hash - or body.get("subaccount_number") - != self.expected_subaccount_number - ): - raise ValueError("broker witness account identity mismatch") - observed = _parse_utc( - body.get("observed_at"), - field="broker witness observed_at", - ) - if observed != signed.not_before: - raise ValueError( - "broker witness observation and signature window differ" - ) - now = self._now_fn() - if now.tzinfo is None or now.utcoffset() is None: - raise ValueError("broker witness clock must be timezone-aware") - if observed > now.astimezone(timezone.utc) + timedelta(seconds=5): - raise ValueError("broker witness is from the future") - return signed - - def verify_terminal_reconciliation_witness( - self, - wrapper: Mapping[str, Any], - ) -> dict[str, Any]: - """Verify a service-signed terminal order/fill projection.""" - signed = self._verify_broker_witness( - wrapper, - expected_schema=TERMINAL_WITNESS_SCHEMA, - ) - body = signed.body - required = { - "schema", - "witness_id", - "venue", - "account_hash", - "subaccount_number", - "reservation_id", - "proposal_id", - "order_id", - "market_ticker", - "contract_ticker", - "side", - "terminal_status", - "initial_count", - "fill_count", - "remaining_count", - "fill_cost_cents", - "fee_cents", - "average_fill_price_cents", - "fill_ids", - "observed_at", - "broker_projection_sha256", - } - if set(body) != required: - raise ValueError("terminal broker witness fields mismatch") - witness_id = _require_sha256( - body["witness_id"], - field="terminal witness_id", - ) - reservation_id = _require_sha256( - body["reservation_id"], - field="terminal reservation_id", - ) - proposal_id = _require_identifier( - body["proposal_id"], - field="terminal proposal_id", - ) - order_id = _require_identifier( - body["order_id"], - field="terminal order_id", - ) - market_ticker = _require_identifier( - body["market_ticker"], - field="terminal market_ticker", - ) - contract_ticker = _require_identifier( - body["contract_ticker"], - field="terminal contract_ticker", - ) - side = body["side"] - if side not in {"yes", "no"}: - raise ValueError("terminal witness side is invalid") - status = body["terminal_status"] - if status not in {"canceled", "executed"}: - raise ValueError("terminal witness status is invalid") - initial_count = _require_int( - body["initial_count"], - field="terminal initial_count", - minimum=1, - ) - fill_count = _require_int( - body["fill_count"], - field="terminal fill_count", - minimum=0, - ) - remaining_count = _require_int( - body["remaining_count"], - field="terminal remaining_count", - minimum=0, - ) - fill_cost = _require_int( - body["fill_cost_cents"], - field="terminal fill_cost_cents", - minimum=0, - ) - fee = _require_int( - body["fee_cents"], - field="terminal fee_cents", - minimum=0, - ) - average = body["average_fill_price_cents"] - fill_ids = body["fill_ids"] - if ( - not isinstance(fill_ids, list) - or fill_ids != sorted(set(fill_ids)) - or any( - not isinstance(item, str) or not item - for item in fill_ids - ) - ): - raise ValueError("terminal fill_ids are invalid") - if ( - fill_count > initial_count - or remaining_count != 0 - or ( - status == "executed" - and fill_count != initial_count - ) - or ( - fill_count == 0 - and ( - fill_cost != 0 - or fee != 0 - or average is not None - or fill_ids - ) - ) - or ( - fill_count > 0 - and ( - isinstance(average, bool) - or not isinstance(average, int) - or not 1 <= average <= 99 - or not fill_ids - or fill_cost < fill_count - or fill_cost > fill_count * 100 - ) - ) - ): - raise ValueError("terminal fill projection is inconsistent") - _require_sha256( - body["broker_projection_sha256"], - field="terminal broker_projection_sha256", - ) - reservation = self._reservation_for_proposal(proposal_id) - if ( - reservation is None - or reservation.get("reservation_id") != reservation_id - or reservation.get("market_ticker") != market_ticker - or reservation.get("contract_ticker") != contract_ticker - or reservation.get("side") != side - or int(reservation.get("size", -1)) != initial_count - ): - raise ValueError( - "terminal witness differs from the capital reservation" - ) - claims = [ - row - for row in self._events("capital.dispatch.claimed") - if row["payload"].get("reservation_id") == reservation_id - ] - if len(claims) != 1: - raise ValueError( - "terminal witness lacks one exact dispatch claim" - ) - if ( - claims[0]["payload"].get("proposal_id") != proposal_id - or claims[0]["payload"].get("client_order_id") - != proposal_id - ): - raise ValueError("terminal dispatch identity mismatch") - observed = _parse_utc( - body["observed_at"], - field="terminal observed_at", - ) - dispatched = _parse_utc( - claims[0]["recorded_at"], - field="dispatch recorded_at", - ) - if observed < dispatched: - raise ValueError( - "terminal witness predates broker dispatch" - ) - if fill_cost + fee > int(reservation["risk_cents"]): - raise ValueError( - "terminal filled risk exceeds the fee-inclusive reservation" - ) - return { - **json.loads(canonical_json(body)), - "signed_event_id": signed.event_id, - "signed_wrapper": signed.wrapper, - "witness_id": witness_id, - "order_id": order_id, - } - - def record_signed_terminal_reconciliation( - self, - wrapper: Mapping[str, Any], - ) -> dict[str, Any]: - """Persist terminal evidence, then move reservation risk to position.""" - witness = self.verify_terminal_reconciliation_witness(wrapper) - reservation_id = str(witness["reservation_id"]) - proposal_id = str(witness["proposal_id"]) - witness_id = str(witness["witness_id"]) - - def validate_terminal(rows: tuple[dict[str, Any], ...]) -> None: - matching = [ - row["payload"] - for row in rows - if row.get("kind") - == "capital.terminal_reconciliation.witnessed" - and row["payload"].get("proposal_id") - == proposal_id - ] - if matching and matching[-1].get("witness_id") != witness_id: - raise ValueError( - "proposal already has a conflicting terminal witness" - ) - if not any( - row.get("kind") == "capital.dispatch.claimed" - and row["payload"].get("reservation_id") - == reservation_id - for row in rows - ): - raise ValueError( - "terminal witness dispatch claim disappeared" - ) - - self.journal.append( - "capital.terminal_reconciliation.witnessed", - { - "witness_id": witness_id, - "proposal_id": proposal_id, - "reservation_id": reservation_id, - "order_id": witness["order_id"], - "terminal_status": witness["terminal_status"], - "fill_count": witness["fill_count"], - "fill_cost_cents": witness["fill_cost_cents"], - "fee_cents": witness["fee_cents"], - "observed_at": witness["observed_at"], - "signed_event_id": witness["signed_event_id"], - "signed_wrapper": witness["signed_wrapper"], - }, - outbox_id=f"capital-terminal-witness:{witness_id}", - validate_existing=validate_terminal, - ) - position: dict[str, Any] | None = None - if int(witness["fill_count"]) > 0: - reservation = self._reservation_for_proposal(proposal_id) - assert reservation is not None - position_id = sha256_json( - { - "schema": CAPITAL_POSITION_EXPOSURE_SCHEMA, - "reservation_id": reservation_id, - "order_id": witness["order_id"], - "terminal_witness_id": witness_id, - } - ) - position = { - "schema": CAPITAL_POSITION_EXPOSURE_SCHEMA, - "position_exposure_id": position_id, - "reservation_id": reservation_id, - "proposal_id": proposal_id, - "order_id": witness["order_id"], - "venue": self.expected_venue, - "account_hash": self.expected_account_hash, - "subaccount_number": self.expected_subaccount_number, - "market_ticker": reservation["market_ticker"], - "contract_ticker": reservation["contract_ticker"], - "correlation_key": reservation["correlation_key"], - "side": reservation["side"], - "fill_count": witness["fill_count"], - "fill_cost_cents": witness["fill_cost_cents"], - "fee_cents": witness["fee_cents"], - "risk_cents": ( - int(witness["fill_cost_cents"]) - + int(witness["fee_cents"]) - ), - "average_fill_price_cents": witness[ - "average_fill_price_cents" - ], - "terminal_witness_id": witness_id, - "observed_at": witness["observed_at"], - } - self.journal.append( - "capital.position.exposure.recorded", - position, - outbox_id=f"capital-position:{position_id}", - ) - - terminal_reservation = self._reservation_for_proposal(proposal_id) - if terminal_reservation is None: - raise ValueError( - "terminal capital reservation disappeared" - ) - release = { - "schema": CAPITAL_TERMINAL_RELEASE_SCHEMA, - "reservation_id": reservation_id, - "proposal_id": proposal_id, - "terminal_witness_id": witness_id, - "terminal_status": witness["terminal_status"], - "released_risk_cents": int( - terminal_reservation["risk_cents"] - ), - "position_exposure_id": ( - position["position_exposure_id"] - if position is not None - else None - ), - } - - def validate_release(rows: tuple[dict[str, Any], ...]) -> None: - if not any( - row.get("kind") - == "capital.terminal_reconciliation.witnessed" - and row["payload"].get("witness_id") == witness_id - for row in rows - ): - raise ValueError("terminal witness is not durable") - if position is not None and not any( - row.get("kind") - == "capital.position.exposure.recorded" - and row["payload"].get("position_exposure_id") - == position["position_exposure_id"] - for row in rows - ): - raise ValueError( - "filled position exposure is not durable" - ) - - self.journal.append( - "capital.reservation.released", - release, - outbox_id=f"capital-terminal-release:{reservation_id}", - validate_existing=validate_release, - ) - return { - "status": "TERMINAL_RECONCILED", - "witness_id": witness_id, - "reservation_id": reservation_id, - "position_exposure_id": ( - position["position_exposure_id"] - if position is not None - else None - ), - } - - def verify_settlement_reconciliation_witness( - self, - wrapper: Mapping[str, Any], - ) -> dict[str, Any]: - """Verify stable position absence plus a service-signed settlement.""" - signed = self._verify_broker_witness( - wrapper, - expected_schema=SETTLEMENT_WITNESS_SCHEMA, - ) - body = signed.body - required = { - "schema", - "witness_id", - "venue", - "account_hash", - "subaccount_number", - "position_exposure_id", - "reservation_id", - "proposal_id", - "contract_ticker", - "side", - "fill_count", - "market_result", - "settled_at", - "revenue_cents", - "settlement_fee_cents", - "position_absent", - "observed_at", - "broker_projection_sha256", - } - if set(body) != required: - raise ValueError("settlement broker witness fields mismatch") - witness_id = _require_sha256( - body["witness_id"], - field="settlement witness_id", - ) - position_id = _require_sha256( - body["position_exposure_id"], - field="position_exposure_id", - ) - _require_sha256( - body["reservation_id"], - field="settlement reservation_id", - ) - _require_identifier( - body["proposal_id"], - field="settlement proposal_id", - ) - _require_identifier( - body["contract_ticker"], - field="settlement contract_ticker", - ) - if body["side"] not in {"yes", "no"}: - raise ValueError("settlement side is invalid") - fill_count = _require_int( - body["fill_count"], - field="settlement fill_count", - minimum=1, - ) - if body["market_result"] not in {"yes", "no"}: - raise ValueError("settlement result is invalid") - settled = _parse_utc( - body["settled_at"], - field="settled_at", - ) - observed = _parse_utc( - body["observed_at"], - field="settlement observed_at", - ) - if settled > observed: - raise ValueError( - "settlement observation predates settlement" - ) - _require_int( - body["revenue_cents"], - field="settlement revenue_cents", - minimum=0, - ) - _require_int( - body["settlement_fee_cents"], - field="settlement fee_cents", - minimum=0, - ) - if body["position_absent"] is not True: - raise ValueError( - "settlement witness lacks stable position absence" - ) - _require_sha256( - body["broker_projection_sha256"], - field="settlement broker_projection_sha256", - ) - positions = [ - row["payload"] - for row in self._events( - "capital.position.exposure.recorded" - ) - if row["payload"].get("position_exposure_id") - == position_id - ] - if len(positions) != 1: - raise ValueError( - "settlement witness lacks one exact capital position" - ) - position = positions[0] - position_observed = _parse_utc( - position.get("observed_at"), - field="capital position observed_at", - ) - if ( - position.get("reservation_id") != body["reservation_id"] - or position.get("proposal_id") != body["proposal_id"] - or position.get("contract_ticker") - != body["contract_ticker"] - or position.get("side") != body["side"] - or int(position.get("fill_count", -1)) != fill_count - ): - raise ValueError( - "settlement witness differs from capital position" - ) - if settled < position_observed: - raise ValueError( - "settlement predates the capital position exposure" - ) - return { - **json.loads(canonical_json(body)), - "signed_event_id": signed.event_id, - "signed_wrapper": signed.wrapper, - "witness_id": witness_id, - } - - def record_signed_settlement_reconciliation( - self, - wrapper: Mapping[str, Any], - ) -> dict[str, Any]: - """Persist settlement evidence before releasing position exposure.""" - witness = self.verify_settlement_reconciliation_witness(wrapper) - witness_id = str(witness["witness_id"]) - position_id = str(witness["position_exposure_id"]) - self.journal.append( - "capital.settlement_reconciliation.witnessed", - { - "witness_id": witness_id, - "position_exposure_id": position_id, - "proposal_id": witness["proposal_id"], - "market_result": witness["market_result"], - "settled_at": witness["settled_at"], - "position_absent": True, - "signed_event_id": witness["signed_event_id"], - "signed_wrapper": witness["signed_wrapper"], - }, - outbox_id=f"capital-settlement-witness:{witness_id}", - ) - position = next( - item - for item in self._events( - "capital.position.exposure.recorded" - ) - if item["payload"].get("position_exposure_id") - == position_id - )["payload"] - release = { - "schema": CAPITAL_POSITION_RELEASE_SCHEMA, - "position_exposure_id": position_id, - "reservation_id": position["reservation_id"], - "proposal_id": position["proposal_id"], - "settlement_witness_id": witness_id, - "released_risk_cents": position["risk_cents"], - "market_result": witness["market_result"], - "settled_at": witness["settled_at"], - } - - def validate_release(rows: tuple[dict[str, Any], ...]) -> None: - if not any( - row.get("kind") - == "capital.settlement_reconciliation.witnessed" - and row["payload"].get("witness_id") == witness_id - for row in rows - ): - raise ValueError("settlement witness is not durable") - - self.journal.append( - "capital.position.exposure.released", - release, - outbox_id=f"capital-position-release:{position_id}", - validate_existing=validate_release, - ) - return { - "status": "POSITION_SETTLED", - "witness_id": witness_id, - "position_exposure_id": position_id, - } - - def release_after_local_reservation_failure( - self, - request: Any, - *, - reservation_id: str, - reason: str, - ) -> dict[str, Any]: - """Retain capital until a sealed broker/local CAS witness exists. - - A caller assertion that transport did not occur is not proof across - process crashes. This recovery surface is intentionally disabled; the - central firewall already retains the reservation on local failure. - """ - del request, reservation_id, reason - raise ValueError( - "local-failure capital release is disabled pending sealed CAS proof" - ) - - def release_from_terminal_reconciliation( - self, - *, - proposal_id: str, - terminal_status: str, - reconciliation_receipt: Mapping[str, Any], - ) -> dict[str, Any] | None: - """Reject caller-authored terminal facts until broker truth is sealed.""" - del proposal_id, terminal_status, reconciliation_receipt - raise ValueError( - "terminal capital release requires a sealed broker witness" - ) - - def enter_cancel_only( - self, - *, - reason: str, - kill_asserted_at: str, - cancel_authorized: bool = False, - cancel_authority_receipt: str | None = None, - ) -> dict[str, Any]: - """Disable submissions without inventing cancellation authority.""" - _parse_utc(kill_asserted_at, field="kill_asserted_at") - authority_receipt = ( - str(cancel_authority_receipt).strip() - if cancel_authority_receipt is not None - else "" - ) - payload = { - "reason": _require_text(reason, field="reason"), - "kill_asserted_at": kill_asserted_at, - "submission_authority": False, - "cancel_authority": False, - "cancel_authority_receipt": None, - "broker_contacted": False, - "status": "CANCEL_AUTHORITY_REQUIRED", - } - event = self.journal.append("authority.cancel_only", payload) - if cancel_authorized or authority_receipt: - raise ValueError( - "cancellation authority requires a verified broker " - "capability; opaque receipt strings are not authority" - ) - return dict(event) - - -__all__ = [ - "CAPITAL_ENVELOPE_SCHEMA", - "CAPITAL_DISPATCH_CLAIM_SCHEMA", - "CAPITAL_RESERVATION_SCHEMA", - "CAPITAL_POSITION_EXPOSURE_SCHEMA", - "CAPITAL_TERMINAL_RELEASE_SCHEMA", - "CAPITAL_POSITION_RELEASE_SCHEMA", - "CapitalEnvelopeAdapter", - "CapitalLineageResolver", - "CapitalVerdict", - "FLAT_BOOTSTRAP_SCHEMA", - "INHERITED_BOOTSTRAP_SCHEMA", - "SIGNED_ENVELOPE_SCHEMA", - "VerifiedCapitalEnvelope", - "VerifiedSignedEnvelope", - "flat_book_receipt", - "inherited_exposure_receipt", - "strategy_binding_hash", - "verify_signed_capital_envelope", - "verify_signed_envelope", -] diff --git a/live_firewall/dumbmoney_command_feed.py b/live_firewall/dumbmoney_command_feed.py deleted file mode 100644 index 5fd6e1bb..00000000 --- a/live_firewall/dumbmoney_command_feed.py +++ /dev/null @@ -1,1722 +0,0 @@ -"""Local-only DumbMoney Core command-feed consumer. - -The consumer has no scheduler, background thread, HTTP client, or broker -interface. A supervised local runner injects one loopback GET transport and -calls :meth:`CoreCommandFeedConsumer.poll_once` explicitly. Every cursor and -its resulting control state are persisted together in the hash-chained, -fsynced operational journal. - -Positive authority is never dispatched through callbacks. Signed LIVE and -kill-clear state becomes visible only through the durable snapshot; injected -handlers are invoked solely for authority-reducing kill/paused controls. -""" -from __future__ import annotations - -import base64 -import hashlib -import json -import re -import secrets -from collections.abc import Callable, Mapping -from copy import deepcopy -from dataclasses import dataclass -from datetime import datetime, timedelta, timezone -from typing import Any, Protocol, cast - -from cryptography.exceptions import InvalidSignature -from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey - -from live_firewall.dumbmoney_capital import ( - CAPITAL_ENVELOPE_SCHEMA, - CapitalEnvelopeAdapter, - VerifiedCapitalEnvelope, - VerifiedSignedEnvelope, - verify_signed_capital_envelope, - verify_signed_envelope, -) -from live_firewall.operational_journal import ( - AppendOnlyOperationalJournal, - canonical_json, - sha256_json, -) - - -CELL_ID = "dummy_kalshi" -PAGE_SCHEMA = "dumbmoney.cell-command-page.v1" -CHECKPOINT_SCHEMA = "dumbmoney.cell-command-checkpoint.v1" -STATE_SCHEMA = "dummy.dumbmoney-command-feed-state.v1" -STATE_EVENT_KIND = "dumbmoney.command-feed.state" -KILL_STATE_SCHEMA = "dumbmoney.kill-state.v1" -DESIRED_MODE_SCHEMA = "dumbmoney.desired-mode.v1" -ZERO_DIGEST = "0" * 64 - -_SHA256_RE = re.compile(r"^[0-9a-f]{64}$") -_IDENTIFIER_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$") -_RFC3339_UTC_RE = re.compile( - r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,6})?Z$" -) -_PAGE_FIELDS = { - "schema", - "cell_id", - "request_nonce", - "observed_at", - "after_sequence", - "after_digest", - "next_sequence", - "next_digest", - "ledger_head_sequence", - "ledger_head_digest", - "has_more", - "required_action", - "commands", - "checkpoint", - "checkpoint_signature", -} -_COMMAND_FIELDS = { - "global_sequence", - "event_id", - "event_digest", - "body_schema", - "valid_now", - "transport_window_current", - "authority_effect", - "ledger_proof", - "envelope", -} -_CHECKPOINT_FIELDS = { - "schema", - "cell_id", - "request_nonce", - "after_sequence", - "after_digest", - "ordered_commands", - "next_sequence", - "next_digest", - "ledger_head_sequence", - "ledger_head_digest", - "observed_at", - "required_action", -} -_CHECKPOINT_COMMAND_FIELDS = _COMMAND_FIELDS - {"envelope"} -_CHECKPOINT_SIGNATURE_FIELDS = {"algorithm", "signer_key_id", "signature"} -_LEDGER_PROOF_FIELDS = { - "schema", - "global_sequence", - "event_id", - "source_id", - "source_sequence", - "signer_key_id", - "nonce", - "event_schema", - "observed_at", - "received_at", - "correlation_id", - "causation_id", - "payload_digest", - "previous_source_digest", - "previous_global_digest", - "event_digest", -} -_LEDGER_PROOF_SCHEMA = "dumbmoney.ledger-event-proof.v1" -_STATE_FIELDS = { - "schema", - "cell_id", - "cursor", - "status", - "reason", - "policy_epoch", - "kill_generation_high_water", - "mode_revision_high_water", - "capital_fencing_high_water", - "kill_envelope", - "desired_mode_envelope", - "required_action", - "updated_at", -} -_ACTIONS = { - "APPLY_SIGNED_CONTROLS", - "PAUSE_NEW_RISK", - "CANCEL_AND_RECONCILE", -} -_MODES = {"READ_ONLY", "PAPER", "LIVE", "PAUSED"} -_AUTHORITY_EFFECTS = { - "APPLY_FAIL_CLOSED", - "APPLY_POSITIVE", - "HISTORICAL_ONLY", -} -_CORE_COMMAND_FUTURE_SKEW = timedelta(seconds=5) -_SUPPORTED_BODY_SCHEMAS = { - KILL_STATE_SCHEMA, - DESIRED_MODE_SCHEMA, - CAPITAL_ENVELOPE_SCHEMA, -} - - -class CommandFeedError(RuntimeError): - """A feed, cursor, signature, or dispatch failure that removes authority.""" - - -@dataclass(frozen=True) -class CommandFeedResponse: - """One injected loopback GET response.""" - - status_code: int - body: bytes - - -class CommandFeedTransport(Protocol): - def __call__( - self, - path: str, - headers: Mapping[str, str], - ) -> CommandFeedResponse: ... - - -@dataclass(frozen=True) -class VerifiedFeedCommand: - global_sequence: int - event_digest: str - envelope: VerifiedSignedEnvelope - ledger_proof: dict[str, Any] - capital: VerifiedCapitalEnvelope | None = None - authority_current: bool = False - authority_current_at_core: bool = False - narrows_authority: bool = False - - @property - def body(self) -> dict[str, Any]: - return deepcopy(self.envelope.body) - - -@dataclass(frozen=True) -class CommandFeedPollResult: - page_accepted: bool - cursor_sequence: int - cursor_digest: str - commands_applied: int - required_action: str | None - submission_allowed: bool - reason: str - - -def _utc_now() -> datetime: - return datetime.now(timezone.utc) - - -def _format_utc(value: datetime) -> str: - if value.tzinfo is None or value.utcoffset() is None: - raise ValueError("timestamp must be timezone-aware") - return value.astimezone(timezone.utc).isoformat().replace("+00:00", "Z") - - -def _parse_utc(value: Any, *, field: str) -> datetime: - if not isinstance(value, str) or not _RFC3339_UTC_RE.fullmatch(value): - raise CommandFeedError(f"{field} must be canonical RFC3339 UTC") - parsed = datetime.fromisoformat(value[:-1] + "+00:00") - return parsed.astimezone(timezone.utc) - - -def _require_int(value: Any, *, field: str, minimum: int = 0) -> int: - if isinstance(value, bool) or not isinstance(value, int) or value < minimum: - raise CommandFeedError(f"{field} must be an integer >= {minimum}") - return value - - -def _require_digest(value: Any, *, field: str) -> str: - if not isinstance(value, str) or not _SHA256_RE.fullmatch(value): - raise CommandFeedError(f"{field} must be a lowercase sha256") - return value - - -def _require_identifier(value: Any, *, field: str) -> str: - if not isinstance(value, str) or not _IDENTIFIER_RE.fullmatch(value): - raise CommandFeedError(f"{field} must be a canonical identifier") - return value - - -def _decode_base64url_signature(value: Any) -> bytes: - if ( - not isinstance(value, str) - or not value - or "=" in value - or re.search(r"[^A-Za-z0-9_-]", value) - ): - raise CommandFeedError( - "checkpoint signature must be unpadded base64url" - ) - try: - decoded = base64.urlsafe_b64decode( - value + "=" * (-len(value) % 4) - ) - except Exception as exc: - raise CommandFeedError("checkpoint signature is invalid base64url") from exc - canonical = ( - base64.urlsafe_b64encode(decoded).decode("ascii").rstrip("=") - ) - if canonical != value or len(decoded) != 64: - raise CommandFeedError("checkpoint signature encoding is invalid") - return decoded - - -def _public_key_bytes(value: bytes | Ed25519PublicKey) -> bytes: - if isinstance(value, Ed25519PublicKey): - return bytes(value.public_bytes_raw()) - raw = bytes(value) - if len(raw) != 32: - raise CommandFeedError("checkpoint Ed25519 public key must be 32 bytes") - return raw - - -def _strict_json(raw: bytes, *, maximum_bytes: int) -> dict[str, Any]: - if not isinstance(raw, bytes): - raise CommandFeedError("command feed response body must be bytes") - if len(raw) > maximum_bytes: - raise CommandFeedError("command feed response exceeds maximum size") - - def pairs_hook(pairs: list[tuple[str, Any]]) -> dict[str, Any]: - value: dict[str, Any] = {} - for key, item in pairs: - if key in value: - raise CommandFeedError("command feed JSON contains duplicate keys") - value[key] = item - return value - - def reject_constant(value: str) -> None: - raise CommandFeedError( - f"command feed JSON contains non-finite constant {value}" - ) - - try: - parsed = json.loads( - raw.decode("utf-8"), - object_pairs_hook=pairs_hook, - parse_constant=reject_constant, - ) - except CommandFeedError: - raise - except (UnicodeDecodeError, json.JSONDecodeError) as exc: - raise CommandFeedError("command feed response is not strict UTF-8 JSON") from exc - if not isinstance(parsed, dict): - raise CommandFeedError("command feed response must be an object") - return parsed - - -def _validate_kill_body( - body: Mapping[str, Any], - *, - now: datetime, - require_current: bool, - future_skew: timedelta, -) -> dict[str, Any]: - required = { - "schema", - "active", - "generation", - "reason", - "changed_by", - "policy_epoch", - "changed_at", - } - if set(body) != required or body.get("schema") != KILL_STATE_SCHEMA: - raise CommandFeedError("kill-state body fields mismatch") - if not isinstance(body["active"], bool): - raise CommandFeedError("kill-state active must be boolean") - _require_int(body["generation"], field="kill-state generation", minimum=1) - if not isinstance(body["reason"], str) or not body["reason"].strip(): - raise CommandFeedError("kill-state reason must be nonempty") - _require_identifier(body["changed_by"], field="kill-state changed_by") - _require_int(body["policy_epoch"], field="kill-state policy_epoch", minimum=1) - changed_at = _parse_utc(body["changed_at"], field="kill-state changed_at") - if require_current and changed_at > now + future_skew: - raise CommandFeedError("kill-state changed_at is from the future") - return cast( - dict[str, Any], - json.loads(canonical_json(dict(body))), - ) - - -def _validate_mode_body( - body: Mapping[str, Any], - *, - now: datetime, - require_current: bool, -) -> dict[str, Any]: - required = { - "schema", - "venue", - "mode", - "revision", - "reason", - "policy_epoch", - "not_before", - "expires_at", - } - if set(body) != required or body.get("schema") != DESIRED_MODE_SCHEMA: - raise CommandFeedError("desired-mode body fields mismatch") - if body["venue"] != CELL_ID: - raise CommandFeedError("desired-mode venue mismatch") - if body["mode"] not in _MODES: - raise CommandFeedError("desired-mode value is unsupported") - _require_int(body["revision"], field="desired-mode revision", minimum=1) - if not isinstance(body["reason"], str) or not body["reason"].strip(): - raise CommandFeedError("desired-mode reason must be nonempty") - _require_int(body["policy_epoch"], field="desired-mode policy_epoch", minimum=1) - not_before = _parse_utc( - body["not_before"], - field="desired-mode not_before", - ) - expires_at = _parse_utc( - body["expires_at"], - field="desired-mode expires_at", - ) - if expires_at <= not_before: - raise CommandFeedError("desired-mode authority window is invalid") - if require_current: - if now < not_before: - raise CommandFeedError("desired-mode is not active yet") - if now >= expires_at: - raise CommandFeedError("desired-mode expired") - return cast( - dict[str, Any], - json.loads(canonical_json(dict(body))), - ) - - -class CoreCommandFeedConsumer: - """Consume one authenticated Core page without any automatic polling.""" - - def __init__( - self, - *, - transport: CommandFeedTransport, - cell_token_provider: Callable[[], str], - state_journal: AppendOnlyOperationalJournal, - trusted_operator_public_keys: Mapping[ - str, - bytes | Ed25519PublicKey, - ], - trusted_checkpoint_public_keys: Mapping[ - str, - bytes | Ed25519PublicKey, - ], - capital_adapter: CapitalEnvelopeAdapter, - kill_handler: Callable[[VerifiedFeedCommand], None], - mode_handler: Callable[[VerifiedFeedCommand], None], - fail_closed_handler: Callable[[str], None], - now_fn: Callable[[], datetime] | None = None, - request_nonce_fn: Callable[[], str] | None = None, - page_limit: int = 250, - maximum_response_bytes: int = 1_048_576, - maximum_page_age: timedelta = timedelta(seconds=60), - maximum_future_skew: timedelta = timedelta(seconds=5), - ) -> None: - if not callable(transport): - raise TypeError("transport must be callable") - if not callable(cell_token_provider): - raise TypeError("cell_token_provider must be callable") - if not callable(kill_handler) or not callable(mode_handler): - raise TypeError("authority-reducing handlers must be callable") - if not callable(fail_closed_handler): - raise TypeError("fail_closed_handler must be callable") - if request_nonce_fn is not None and not callable(request_nonce_fn): - raise TypeError("request_nonce_fn must be callable") - if isinstance(page_limit, bool) or not 1 <= page_limit <= 1000: - raise ValueError("page_limit must be between 1 and 1000") - if maximum_response_bytes < 1: - raise ValueError("maximum_response_bytes must be positive") - if maximum_page_age <= timedelta(0): - raise ValueError("maximum_page_age must be positive") - if maximum_future_skew < timedelta(0): - raise ValueError("maximum_future_skew cannot be negative") - if capital_adapter.expected_venue != CELL_ID: - raise ValueError("capital adapter must be pinned to dummy_kalshi") - if not trusted_checkpoint_public_keys: - raise ValueError("at least one pinned Core checkpoint key is required") - if not trusted_operator_public_keys: - raise ValueError( - "at least one pinned operator command key is required" - ) - checkpoint_keys: dict[str, bytes] = {} - for key_id, key_material in trusted_checkpoint_public_keys.items(): - normalized_key_id = _require_digest( - key_id, - field="checkpoint signer key id", - ) - raw_key = _public_key_bytes(key_material) - if hashlib.sha256(raw_key).hexdigest() != normalized_key_id: - raise ValueError( - "checkpoint signer key id does not match public key" - ) - checkpoint_keys[normalized_key_id] = raw_key - operator_keys: dict[str, bytes] = {} - for key_id, key_material in trusted_operator_public_keys.items(): - normalized_key_id = _require_digest( - key_id, - field="operator signer key id", - ) - raw_key = _public_key_bytes(key_material) - if hashlib.sha256(raw_key).hexdigest() != normalized_key_id: - raise ValueError( - "operator signer key id does not match public key" - ) - operator_keys[normalized_key_id] = raw_key - if set(checkpoint_keys) & set(operator_keys): - raise ValueError( - "Core checkpoint and operator command keys must be disjoint" - ) - if not set(checkpoint_keys) <= set( - capital_adapter.trusted_public_keys - ): - raise ValueError( - "capital adapter must trust every pinned Core checkpoint key" - ) - - self._transport = transport - self._cell_token_provider = cell_token_provider - self._journal = state_journal - self._trusted_operator_public_keys = operator_keys - self._trusted_checkpoint_public_keys = checkpoint_keys - self._capital_adapter = capital_adapter - self._kill_handler = kill_handler - self._mode_handler = mode_handler - self._fail_closed_handler = fail_closed_handler - self._now_fn = now_fn or _utc_now - self._request_nonce_fn = request_nonce_fn or ( - lambda: secrets.token_hex(32) - ) - self._last_request_nonce: str | None = None - self.page_limit = page_limit - self.maximum_response_bytes = maximum_response_bytes - self.maximum_page_age = maximum_page_age - self.maximum_future_skew = maximum_future_skew - - def _now(self) -> datetime: - now = self._now_fn() - if now.tzinfo is None or now.utcoffset() is None: - raise CommandFeedError("command-feed clock must be timezone-aware") - return now.astimezone(timezone.utc) - - def _bootstrap_state(self, now: datetime) -> dict[str, Any]: - return { - "schema": STATE_SCHEMA, - "cell_id": CELL_ID, - "cursor": {"sequence": 0, "digest": ZERO_DIGEST}, - "status": "FAIL_CLOSED", - "reason": "explicit bootstrap cursor has not been polled", - "policy_epoch": 0, - "kill_generation_high_water": 0, - "mode_revision_high_water": 0, - "capital_fencing_high_water": 0, - "kill_envelope": None, - "desired_mode_envelope": None, - "required_action": None, - "updated_at": _format_utc(now), - } - - def _validate_stored_state( - self, - raw: Mapping[str, Any], - *, - now: datetime, - ) -> dict[str, Any]: - state = json.loads(canonical_json(dict(raw))) - if set(state) != _STATE_FIELDS: - raise CommandFeedError("persisted command-feed state fields mismatch") - if state["schema"] != STATE_SCHEMA or state["cell_id"] != CELL_ID: - raise CommandFeedError("persisted command-feed state identity mismatch") - cursor = state["cursor"] - if not isinstance(cursor, dict) or set(cursor) != {"sequence", "digest"}: - raise CommandFeedError("persisted command-feed cursor fields mismatch") - _require_int(cursor["sequence"], field="cursor sequence") - _require_digest(cursor["digest"], field="cursor digest") - if cursor["sequence"] == 0 and cursor["digest"] != ZERO_DIGEST: - raise CommandFeedError("bootstrap cursor digest mismatch") - if cursor["sequence"] > 0 and cursor["digest"] == ZERO_DIGEST: - raise CommandFeedError("non-bootstrap cursor cannot use zero digest") - if state["status"] not in {"READY", "CATCHING_UP", "FAIL_CLOSED"}: - raise CommandFeedError("persisted command-feed status is unsupported") - if not isinstance(state["reason"], str) or not state["reason"].strip(): - raise CommandFeedError("persisted command-feed reason is missing") - _require_int(state["policy_epoch"], field="persisted policy_epoch") - _require_int( - state["kill_generation_high_water"], - field="persisted kill generation high-water", - ) - _require_int( - state["mode_revision_high_water"], - field="persisted mode revision high-water", - ) - _require_int( - state["capital_fencing_high_water"], - field="persisted capital fence high-water", - ) - if state["required_action"] is not None: - if state["required_action"] not in _ACTIONS: - raise CommandFeedError("persisted required_action is unsupported") - _parse_utc(state["updated_at"], field="persisted updated_at") - - kill = state["kill_envelope"] - if kill is not None: - signed = verify_signed_envelope( - kill, - trusted_public_keys=self._trusted_operator_public_keys, - expected_body_schema=KILL_STATE_SCHEMA, - require_active=False, - ) - _validate_kill_body( - signed.body, - now=now, - require_current=False, - future_skew=self.maximum_future_skew, - ) - if ( - int(signed.body["generation"]) - > int(state["kill_generation_high_water"]) - ): - raise CommandFeedError( - "persisted kill generation exceeds high-water" - ) - mode = state["desired_mode_envelope"] - if mode is not None: - signed = verify_signed_envelope( - mode, - trusted_public_keys=self._trusted_operator_public_keys, - expected_body_schema=DESIRED_MODE_SCHEMA, - require_active=False, - ) - _validate_mode_body( - signed.body, - now=now, - require_current=False, - ) - if ( - int(signed.body["revision"]) - > int(state["mode_revision_high_water"]) - ): - raise CommandFeedError( - "persisted mode revision exceeds high-water" - ) - return cast(dict[str, Any], state) - - def _load_state(self, *, now: datetime) -> dict[str, Any]: - rows = self._journal.events(kind=STATE_EVENT_KIND) - if not rows: - return self._bootstrap_state(now) - return self._validate_stored_state(rows[-1]["payload"], now=now) - - @staticmethod - def _cursor(state: Mapping[str, Any]) -> tuple[int, str]: - cursor = state["cursor"] - return int(cursor["sequence"]), str(cursor["digest"]) - - def snapshot(self) -> dict[str, Any]: - """Return the latest durable state; an invalid journal raises closed.""" - return deepcopy(self._load_state(now=self._now())) - - def submission_allowed(self) -> bool: - """Return only durable, current mode/kill authority. - - Capital, Dummy-local risk, and broker/session gates remain independent - mandatory checks at the execution sink. - """ - try: - now = self._now() - state = self._load_state(now=now) - return ( - state["status"] == "READY" - and self._state_action(state, now=now) - == "APPLY_SIGNED_CONTROLS" - ) - except Exception: - return False - - def _request_path( - self, - sequence: int, - digest: str, - request_nonce: str, - ) -> str: - return ( - f"/v1/cells/{CELL_ID}/commands" - f"?after={sequence}&cursor={digest}" - f"&request_nonce={request_nonce}&limit={self.page_limit}" - ) - - def _verify_checkpoint( - self, - checkpoint_raw: Any, - signature_raw: Any, - ) -> dict[str, Any]: - if not isinstance(checkpoint_raw, dict): - raise CommandFeedError("command checkpoint must be an object") - if not isinstance(signature_raw, dict): - raise CommandFeedError( - "command checkpoint signature must be an object" - ) - checkpoint = json.loads(canonical_json(checkpoint_raw)) - signature = json.loads(canonical_json(signature_raw)) - if ( - set(checkpoint) != _CHECKPOINT_FIELDS - or checkpoint.get("schema") != CHECKPOINT_SCHEMA - ): - raise CommandFeedError("command checkpoint fields mismatch") - if set(signature) != _CHECKPOINT_SIGNATURE_FIELDS: - raise CommandFeedError( - "command checkpoint signature fields mismatch" - ) - if signature["algorithm"] != "Ed25519": - raise CommandFeedError( - "command checkpoint signature algorithm mismatch" - ) - signer_key_id = _require_digest( - signature["signer_key_id"], - field="checkpoint signer_key_id", - ) - public_key = self._trusted_checkpoint_public_keys.get(signer_key_id) - if public_key is None: - raise CommandFeedError("command checkpoint signer is not pinned") - encoded_signature = _decode_base64url_signature( - signature["signature"] - ) - try: - Ed25519PublicKey.from_public_bytes(public_key).verify( - encoded_signature, - canonical_json(checkpoint).encode("utf-8"), - ) - except (InvalidSignature, ValueError) as exc: - raise CommandFeedError( - "command checkpoint signature is invalid" - ) from exc - return cast(dict[str, Any], checkpoint) - - @staticmethod - def _validate_ledger_proof( - proof_raw: Any, - *, - sequence: int, - event_id: str, - event_digest: str, - body_schema: str, - envelope: VerifiedSignedEnvelope, - page_observed_at: datetime, - ) -> dict[str, Any]: - if not isinstance(proof_raw, dict): - raise CommandFeedError("command ledger_proof must be an object") - proof = json.loads(canonical_json(proof_raw)) - if ( - set(proof) != _LEDGER_PROOF_FIELDS - or proof.get("schema") != _LEDGER_PROOF_SCHEMA - ): - raise CommandFeedError("command ledger_proof fields mismatch") - proof_sequence = _require_int( - proof["global_sequence"], - field="ledger proof global_sequence", - minimum=1, - ) - proof_event_id = _require_digest( - proof["event_id"], - field="ledger proof event_id", - ) - proof_event_digest = _require_digest( - proof["event_digest"], - field="ledger proof event_digest", - ) - proof_source_id = _require_identifier( - proof["source_id"], - field="ledger proof source_id", - ) - proof_source_sequence = _require_int( - proof["source_sequence"], - field="ledger proof source_sequence", - minimum=1, - ) - proof_signer = _require_digest( - proof["signer_key_id"], - field="ledger proof signer_key_id", - ) - proof_nonce = _require_identifier( - proof["nonce"], - field="ledger proof nonce", - ) - proof_schema = _require_identifier( - proof["event_schema"], - field="ledger proof event_schema", - ) - proof_correlation = _require_identifier( - proof["correlation_id"], - field="ledger proof correlation_id", - ) - proof_causation = proof["causation_id"] - if proof_causation is not None: - _require_digest( - proof_causation, - field="ledger proof causation_id", - ) - payload_digest = _require_digest( - proof["payload_digest"], - field="ledger proof payload_digest", - ) - previous_source_digest = _require_digest( - proof["previous_source_digest"], - field="ledger proof previous_source_digest", - ) - previous_global_digest = _require_digest( - proof["previous_global_digest"], - field="ledger proof previous_global_digest", - ) - record_observed_at = _parse_utc( - proof["observed_at"], - field="ledger proof observed_at", - ) - received_at = _parse_utc( - proof["received_at"], - field="ledger proof received_at", - ) - if received_at > page_observed_at: - raise CommandFeedError( - "ledger proof was received after page observation" - ) - if record_observed_at != max(received_at, envelope.not_before): - raise CommandFeedError( - "ledger proof observed_at differs from ingestion semantics" - ) - if proof_sequence == 1 and previous_global_digest != ZERO_DIGEST: - raise CommandFeedError( - "first ledger event previous_global_digest mismatch" - ) - if proof_sequence > 1 and previous_global_digest == ZERO_DIGEST: - raise CommandFeedError( - "noninitial ledger event has zero previous_global_digest" - ) - if proof_source_sequence == 1 and previous_source_digest != ZERO_DIGEST: - raise CommandFeedError( - "first source event previous_source_digest mismatch" - ) - if proof_source_sequence > 1 and previous_source_digest == ZERO_DIGEST: - raise CommandFeedError( - "noninitial source event has zero previous_source_digest" - ) - - wrapper = envelope.wrapper - duplicated = { - "global_sequence": (proof_sequence, sequence), - "event_id": (proof_event_id, event_id), - "event_digest": (proof_event_digest, event_digest), - "source_id": (proof_source_id, envelope.source_id), - "source_sequence": ( - proof_source_sequence, - envelope.source_sequence, - ), - "signer_key_id": (proof_signer, envelope.signer_key_id), - "nonce": (proof_nonce, envelope.nonce), - "event_schema": (proof_schema, body_schema), - "correlation_id": ( - proof_correlation, - wrapper["correlation_id"], - ), - "causation_id": ( - proof_causation, - wrapper["causation_id"], - ), - "payload_digest": ( - payload_digest, - wrapper["body_digest"], - ), - } - for field, (proof_value, expected_value) in duplicated.items(): - if proof_value != expected_value: - raise CommandFeedError( - f"ledger proof {field} differs from command envelope" - ) - - event_material = { - key: value - for key, value in proof.items() - if key not in {"schema", "event_digest"} - } - if sha256_json(event_material) != proof_event_digest: - raise CommandFeedError( - "ledger proof event_digest does not match event material" - ) - return cast(dict[str, Any], proof) - - def _decode_command( - self, - raw: Any, - *, - now: datetime, - observed_at: datetime, - after_sequence: int, - next_sequence: int, - ) -> VerifiedFeedCommand: - if not isinstance(raw, dict) or set(raw) != _COMMAND_FIELDS: - raise CommandFeedError("command record fields mismatch") - sequence = _require_int( - raw["global_sequence"], - field="command global_sequence", - minimum=1, - ) - if not after_sequence < sequence <= next_sequence: - raise CommandFeedError("command sequence falls outside page cursor range") - event_id = _require_digest(raw["event_id"], field="command event_id") - event_digest = _require_digest( - raw["event_digest"], - field="command event_digest", - ) - body_schema = _require_identifier( - raw["body_schema"], - field="command body_schema", - ) - if body_schema not in _SUPPORTED_BODY_SCHEMAS: - raise CommandFeedError("command body schema is unsupported") - if not isinstance(raw["valid_now"], bool): - raise CommandFeedError("command valid_now must be boolean") - if not isinstance(raw["transport_window_current"], bool): - raise CommandFeedError( - "command transport_window_current must be boolean" - ) - if raw["authority_effect"] not in _AUTHORITY_EFFECTS: - raise CommandFeedError("command authority_effect is unsupported") - envelope_raw = raw["envelope"] - if not isinstance(envelope_raw, dict): - raise CommandFeedError("command envelope must be an object") - try: - command_keys = ( - self._trusted_checkpoint_public_keys - if body_schema == CAPITAL_ENVELOPE_SCHEMA - else self._trusted_operator_public_keys - ) - signed = verify_signed_envelope( - envelope_raw, - trusted_public_keys=command_keys, - expected_body_schema=body_schema, - require_active=False, - ) - except ValueError as exc: - raise CommandFeedError(f"signed command invalid: {exc}") from exc - if signed.event_id != event_id: - raise CommandFeedError("command event_id differs from signed envelope") - ledger_proof = self._validate_ledger_proof( - raw["ledger_proof"], - sequence=sequence, - event_id=event_id, - event_digest=event_digest, - body_schema=body_schema, - envelope=signed, - page_observed_at=observed_at, - ) - core_window_active = ( - signed.not_before <= observed_at < signed.expires_at - ) - if raw["transport_window_current"] is not core_window_active: - raise CommandFeedError( - "transport_window_current differs from signed envelope" - ) - local_window_active = signed.not_before <= now < signed.expires_at - - capital: VerifiedCapitalEnvelope | None = None - narrows_authority = False - body_current_at_core = True - body_current_locally = True - if body_schema == KILL_STATE_SCHEMA: - _validate_kill_body( - signed.body, - now=now, - require_current=False, - future_skew=self.maximum_future_skew, - ) - narrows_authority = signed.body["active"] is True - changed_at = _parse_utc( - signed.body["changed_at"], - field="kill-state changed_at", - ) - body_current_at_core = ( - changed_at <= observed_at + _CORE_COMMAND_FUTURE_SKEW - ) - body_current_locally = ( - changed_at <= now + _CORE_COMMAND_FUTURE_SKEW - ) - elif body_schema == DESIRED_MODE_SCHEMA: - _validate_mode_body( - signed.body, - now=now, - require_current=False, - ) - narrows_authority = signed.body["mode"] != "LIVE" - body_not_before = _parse_utc( - signed.body["not_before"], - field="desired-mode not_before", - ) - body_expires_at = _parse_utc( - signed.body["expires_at"], - field="desired-mode expires_at", - ) - body_current_at_core = ( - body_not_before <= observed_at < body_expires_at - ) - body_current_locally = ( - body_not_before <= now < body_expires_at - ) - else: - try: - capital = verify_signed_capital_envelope( - envelope_raw, - trusted_public_keys=self._trusted_checkpoint_public_keys, - expected_venue=CELL_ID, - expected_account_hash=( - self._capital_adapter.expected_account_hash - ), - now=now, - max_ttl=self._capital_adapter.max_envelope_ttl, - require_active=False, - ) - except ValueError as exc: - raise CommandFeedError( - f"signed capital command invalid: {exc}" - ) from exc - body_current_at_core = ( - capital.not_before <= observed_at < capital.expires_at - ) - body_current_locally = ( - capital.not_before <= now < capital.expires_at - ) - valid_at_core = core_window_active and body_current_at_core - if raw["valid_now"] is not valid_at_core: - raise CommandFeedError( - "command valid_now differs from signed authority state" - ) - positive_grant = not narrows_authority - expected_effect = ( - "APPLY_FAIL_CLOSED" - if not positive_grant - else "APPLY_POSITIVE" - if valid_at_core - else "HISTORICAL_ONLY" - ) - if raw["authority_effect"] != expected_effect: - raise CommandFeedError( - "command authority_effect differs from signed authority state" - ) - authority_current = ( - local_window_active and body_current_locally - ) - return VerifiedFeedCommand( - global_sequence=sequence, - event_digest=event_digest, - envelope=signed, - ledger_proof=ledger_proof, - capital=capital, - authority_current=authority_current, - authority_current_at_core=valid_at_core, - narrows_authority=narrows_authority, - ) - - def _decode_page( - self, - response: CommandFeedResponse, - *, - state: Mapping[str, Any], - now: datetime, - expected_request_nonce: str, - ) -> tuple[dict[str, Any], list[VerifiedFeedCommand]]: - if isinstance(response.status_code, bool) or not isinstance( - response.status_code, - int, - ): - raise CommandFeedError("command feed response status is invalid") - if response.status_code in {401, 403}: - raise CommandFeedError("cell bearer authentication failed") - if response.status_code == 409: - raise CommandFeedError("Core rejected the persisted cursor") - if response.status_code != 200: - raise CommandFeedError( - f"command feed returned HTTP {response.status_code}" - ) - page = _strict_json( - response.body, - maximum_bytes=self.maximum_response_bytes, - ) - if set(page) != _PAGE_FIELDS: - raise CommandFeedError("command page fields mismatch") - if page["schema"] != PAGE_SCHEMA: - raise CommandFeedError("command page schema mismatch") - - # The checkpoint authenticates every authority-bearing projection - # except the independently signed command envelopes. Verify it before - # trusting cursors, action, timing, or command metadata. - checkpoint = self._verify_checkpoint( - page["checkpoint"], - page["checkpoint_signature"], - ) - mirrored_fields = { - "cell_id", - "request_nonce", - "observed_at", - "after_sequence", - "after_digest", - "next_sequence", - "next_digest", - "ledger_head_sequence", - "ledger_head_digest", - "required_action", - } - for field in mirrored_fields: - if canonical_json(page[field]) != canonical_json(checkpoint[field]): - raise CommandFeedError( - f"command page {field} differs from signed checkpoint" - ) - if checkpoint["cell_id"] != CELL_ID: - raise CommandFeedError("command page identity mismatch") - request_nonce = _require_digest( - checkpoint["request_nonce"], - field="checkpoint request_nonce", - ) - if request_nonce != expected_request_nonce: - raise CommandFeedError( - "checkpoint request_nonce differs from current request" - ) - - if not isinstance(page["commands"], list): - raise CommandFeedError("command page commands must be an array") - ordered_commands = checkpoint["ordered_commands"] - if not isinstance(ordered_commands, list): - raise CommandFeedError( - "checkpoint ordered_commands must be an array" - ) - if len(ordered_commands) != len(page["commands"]): - raise CommandFeedError( - "checkpoint command count differs from page" - ) - for raw_command, projected in zip( - page["commands"], - ordered_commands, - strict=True, - ): - if not isinstance(raw_command, dict): - raise CommandFeedError("command record must be an object") - if ( - not isinstance(projected, dict) - or set(projected) != _CHECKPOINT_COMMAND_FIELDS - ): - raise CommandFeedError( - "checkpoint command projection fields mismatch" - ) - projection = { - key: value - for key, value in raw_command.items() - if key != "envelope" - } - if canonical_json(projection) != canonical_json(projected): - raise CommandFeedError( - "page command differs from signed checkpoint projection" - ) - - observed_at = _parse_utc(page["observed_at"], field="page observed_at") - if observed_at > now + self.maximum_future_skew: - raise CommandFeedError("command page observation is from the future") - if now - observed_at > self.maximum_page_age: - raise CommandFeedError("command page observation is stale") - - current_sequence, current_digest = self._cursor(state) - after_sequence = _require_int( - page["after_sequence"], - field="page after_sequence", - ) - after_digest = _require_digest( - page["after_digest"], - field="page after_digest", - ) - if (after_sequence, after_digest) != ( - current_sequence, - current_digest, - ): - raise CommandFeedError("command page does not continue persisted cursor") - next_sequence = _require_int( - page["next_sequence"], - field="page next_sequence", - ) - next_digest = _require_digest( - page["next_digest"], - field="page next_digest", - ) - ledger_head = _require_int( - page["ledger_head_sequence"], - field="page ledger_head_sequence", - ) - ledger_head_digest = _require_digest( - page["ledger_head_digest"], - field="page ledger_head_digest", - ) - if not after_sequence <= next_sequence <= ledger_head: - raise CommandFeedError("command page cursor range is invalid") - if after_sequence == 0 and after_digest != ZERO_DIGEST: - raise CommandFeedError("bootstrap cursor digest mismatch") - if after_sequence > 0 and after_digest == ZERO_DIGEST: - raise CommandFeedError("non-bootstrap cursor has zero digest") - if ledger_head == 0 and ledger_head_digest != ZERO_DIGEST: - raise CommandFeedError("empty ledger head digest mismatch") - if ledger_head > 0 and ledger_head_digest == ZERO_DIGEST: - raise CommandFeedError("nonempty ledger head has zero digest") - if ledger_head == next_sequence and ledger_head_digest != next_digest: - raise CommandFeedError( - "page cursor digest differs from ledger head" - ) - if next_sequence - after_sequence > self.page_limit: - raise CommandFeedError("command page contains a ledger sequence gap") - if next_sequence == after_sequence and next_digest != after_digest: - raise CommandFeedError("stationary cursor digest mismatch") - if next_sequence > after_sequence and next_digest == after_digest: - raise CommandFeedError("advancing cursor digest did not change") - if next_sequence > 0 and next_digest == ZERO_DIGEST: - raise CommandFeedError("advancing cursor cannot use zero digest") - if page["has_more"] is not (next_sequence < ledger_head): - raise CommandFeedError("command page has_more is inconsistent") - if page["required_action"] not in _ACTIONS: - raise CommandFeedError("command page required_action is unsupported") - if len(page["commands"]) > self.page_limit: - raise CommandFeedError("command page exceeds requested limit") - - commands = [ - self._decode_command( - item, - now=now, - observed_at=observed_at, - after_sequence=after_sequence, - next_sequence=next_sequence, - ) - for item in page["commands"] - ] - sequences = [command.global_sequence for command in commands] - if sequences != sorted(set(sequences)): - raise CommandFeedError("command sequences are not strictly increasing") - previous_command: VerifiedFeedCommand | None = None - latest_source_command: dict[ - str, - VerifiedFeedCommand, - ] = {} - for command in commands: - proof = command.ledger_proof - if ( - previous_command is None - and command.global_sequence == after_sequence + 1 - and proof["previous_global_digest"] != after_digest - ): - raise CommandFeedError( - "first command does not extend persisted cursor" - ) - if ( - previous_command is not None - and command.global_sequence - == previous_command.global_sequence + 1 - and proof["previous_global_digest"] - != previous_command.event_digest - ): - raise CommandFeedError( - "adjacent command ledger chain is discontinuous" - ) - prior_source = latest_source_command.get(command.envelope.source_id) - if prior_source is not None: - current_source_sequence = command.envelope.source_sequence - prior_source_sequence = prior_source.envelope.source_sequence - if current_source_sequence <= prior_source_sequence: - raise CommandFeedError( - "command source sequence is not increasing" - ) - if ( - current_source_sequence == prior_source_sequence + 1 - and proof["previous_source_digest"] - != prior_source.event_digest - ): - raise CommandFeedError( - "adjacent source command chain is discontinuous" - ) - latest_source_command[command.envelope.source_id] = command - previous_command = command - if next_sequence == after_sequence and commands: - raise CommandFeedError("stationary command page cannot contain commands") - last_at_cursor = next( - ( - command - for command in reversed(commands) - if command.global_sequence == next_sequence - ), - None, - ) - if last_at_cursor is not None and last_at_cursor.event_digest != next_digest: - raise CommandFeedError("command event digest differs from page cursor") - return page, commands - - def _stage_commands( - self, - state: Mapping[str, Any], - commands: list[VerifiedFeedCommand], - *, - now: datetime, - use_core_authority: bool = False, - ) -> tuple[dict[str, Any], int, bool]: - staged = deepcopy(dict(state)) - policy_epoch = int(staged["policy_epoch"]) - applied_count = 0 - ignored_positive = False - for command in commands: - authority_current = ( - command.authority_current_at_core - if use_core_authority - else command.authority_current - ) - body = command.envelope.body - command_epoch = _require_int( - body["policy_epoch"], - field="command policy_epoch", - minimum=1, - ) - if command_epoch < policy_epoch: - raise CommandFeedError("command policy epoch regressed") - policy_epoch = max(policy_epoch, command_epoch) - if command.envelope.body_schema == KILL_STATE_SCHEMA: - generation = int(body["generation"]) - high_water = int(staged["kill_generation_high_water"]) - if generation <= high_water: - raise CommandFeedError( - "kill-state generation did not advance" - ) - staged["kill_generation_high_water"] = generation - if command.narrows_authority or authority_current: - staged["kill_envelope"] = command.envelope.wrapper - applied_count += 1 - else: - ignored_positive = True - elif command.envelope.body_schema == DESIRED_MODE_SCHEMA: - revision = int(body["revision"]) - high_water = int(staged["mode_revision_high_water"]) - if revision <= high_water: - raise CommandFeedError( - "desired-mode revision did not advance" - ) - staged["mode_revision_high_water"] = revision - if command.narrows_authority or authority_current: - staged["desired_mode_envelope"] = command.envelope.wrapper - applied_count += 1 - else: - ignored_positive = True - else: - if command.capital is None: - raise CommandFeedError( - "capital command lacks verified body" - ) - fence = command.capital.fencing_generation - high_water = int(staged["capital_fencing_high_water"]) - if fence <= high_water: - raise CommandFeedError( - "capital fencing generation did not advance" - ) - staged["capital_fencing_high_water"] = fence - if authority_current: - applied_count += 1 - else: - ignored_positive = True - staged["policy_epoch"] = policy_epoch - staged["updated_at"] = _format_utc(now) - return staged, applied_count, ignored_positive - - def _state_action( - self, - state: Mapping[str, Any], - *, - now: datetime, - ) -> str: - kill = state["kill_envelope"] - mode = state["desired_mode_envelope"] - if kill is not None and kill["body"]["active"] is True: - return "CANCEL_AND_RECONCILE" - if mode is None: - return "PAUSE_NEW_RISK" - if mode["body"]["mode"] != "LIVE": - return "PAUSE_NEW_RISK" - mode_not_before = _parse_utc( - mode["not_before"], - field="desired-mode wrapper not_before", - ) - mode_expires_at = _parse_utc( - mode["expires_at"], - field="desired-mode wrapper expires_at", - ) - if not mode_not_before <= now < mode_expires_at: - return "PAUSE_NEW_RISK" - try: - _validate_mode_body( - mode["body"], - now=now, - require_current=True, - ) - except CommandFeedError: - return "PAUSE_NEW_RISK" - if kill is None or kill["body"]["active"] is not False: - return "PAUSE_NEW_RISK" - kill_not_before = _parse_utc( - kill["not_before"], - field="kill-state wrapper not_before", - ) - kill_expires_at = _parse_utc( - kill["expires_at"], - field="kill-state wrapper expires_at", - ) - if not kill_not_before <= now < kill_expires_at: - return "PAUSE_NEW_RISK" - _validate_kill_body( - kill["body"], - now=now, - require_current=True, - future_skew=self.maximum_future_skew, - ) - return "APPLY_SIGNED_CONTROLS" - - def _persist_state( - self, - state: Mapping[str, Any], - *, - expected_cursor: tuple[int, str], - ) -> None: - next_cursor = self._cursor(state) - - def validate_existing(rows: tuple[dict[str, Any], ...]) -> None: - prior_states = [ - row - for row in rows - if row.get("kind") == STATE_EVENT_KIND - ] - actual_cursor = ( - (0, ZERO_DIGEST) - if not prior_states - else self._cursor(prior_states[-1]["payload"]) - ) - if actual_cursor != expected_cursor: - raise CommandFeedError( - "command-feed cursor changed during poll" - ) - if next_cursor[0] < actual_cursor[0]: - raise CommandFeedError("command-feed cursor cannot regress") - if ( - next_cursor[0] == actual_cursor[0] - and next_cursor[1] != actual_cursor[1] - ): - raise CommandFeedError( - "stationary command-feed cursor digest changed" - ) - - self._journal.append( - STATE_EVENT_KIND, - dict(state), - validate_existing=validate_existing, - validate_existing_latest_kinds=(STATE_EVENT_KIND,), - ) - - def _fail_closed( - self, - *, - state: Mapping[str, Any], - reason: str, - now: datetime, - ) -> CommandFeedPollResult: - safe_reason = str(reason).strip()[:512] or "command feed failed closed" - try: - self._fail_closed_handler(safe_reason) - except Exception as exc: - safe_reason = ( - f"{safe_reason}; fail-closed handler failed:{type(exc).__name__}" - )[:512] - failed = deepcopy(dict(state)) - failed["status"] = "FAIL_CLOSED" - failed["reason"] = safe_reason - failed["updated_at"] = _format_utc(now) - try: - self._persist_state( - failed, - expected_cursor=self._cursor(state), - ) - except Exception as exc: - safe_reason = ( - f"{safe_reason}; state persistence failed:{type(exc).__name__}" - )[:512] - sequence, digest = self._cursor(state) - return CommandFeedPollResult( - page_accepted=False, - cursor_sequence=sequence, - cursor_digest=digest, - commands_applied=0, - required_action=state.get("required_action"), - submission_allowed=False, - reason=safe_reason, - ) - - def poll_once(self) -> CommandFeedPollResult: - """Serialize and apply at most one page across local runner processes.""" - try: - with self._journal.serialized_operation(): - return self._poll_once_serialized() - except Exception as exc: - try: - self._fail_closed_handler( - f"command operation lock failed:{type(exc).__name__}" - ) - except Exception: - pass - return CommandFeedPollResult( - page_accepted=False, - cursor_sequence=0, - cursor_digest=ZERO_DIGEST, - commands_applied=0, - required_action=None, - submission_allowed=False, - reason=( - f"command operation lock failed:{type(exc).__name__}" - ), - ) - - def _poll_once_serialized(self) -> CommandFeedPollResult: - """Fetch, verify, dispatch, and durably advance at most one page. - - There are no retries. The injected transport is called exactly once, - and no method in this module can submit or cancel a broker order. - """ - now = self._now() - try: - state = self._load_state(now=now) - except Exception as exc: - bootstrap = self._bootstrap_state(now) - return self._fail_closed( - state=bootstrap, - reason=f"persisted cursor unavailable:{type(exc).__name__}", - now=now, - ) - - try: - token = self._cell_token_provider() - except Exception as exc: - return self._fail_closed( - state=state, - reason=f"cell token unavailable:{type(exc).__name__}", - now=now, - ) - if ( - not isinstance(token, str) - or not token - or token != token.strip() - or "\r" in token - or "\n" in token - ): - return self._fail_closed( - state=state, - reason="cell token is not a canonical secret", - now=now, - ) - - sequence, digest = self._cursor(state) - try: - request_nonce = self._request_nonce_fn() - except Exception as exc: - return self._fail_closed( - state=state, - reason=f"request nonce unavailable:{type(exc).__name__}", - now=now, - ) - try: - request_nonce = _require_digest( - request_nonce, - field="request nonce", - ) - except CommandFeedError as exc: - return self._fail_closed( - state=state, - reason=str(exc), - now=now, - ) - if request_nonce == self._last_request_nonce: - return self._fail_closed( - state=state, - reason="request nonce generator repeated a nonce", - now=now, - ) - self._last_request_nonce = request_nonce - path = self._request_path(sequence, digest, request_nonce) - try: - response = self._transport( - path, - {"Authorization": f"Bearer {token}"}, - ) - except Exception as exc: - return self._fail_closed( - state=state, - reason=f"command feed transport failed:{type(exc).__name__}", - now=now, - ) - finally: - token = "" - if not isinstance(response, CommandFeedResponse): - return self._fail_closed( - state=state, - reason="command feed transport returned an unsupported response", - now=now, - ) - - try: - received_now = self._now() - page, commands = self._decode_page( - response, - state=state, - now=received_now, - expected_request_nonce=request_nonce, - ) - page_observed_at = _parse_utc( - page["observed_at"], - field="page observed_at", - ) - core_staged, _, _ = self._stage_commands( - state, - commands, - now=page_observed_at, - use_core_authority=True, - ) - expected_core_action = self._state_action( - core_staged, - now=page_observed_at, - ) - if ( - page["has_more"] is False - and page["required_action"] != expected_core_action - ): - raise CommandFeedError( - "Core required_action differs from verified local state" - ) - staged, applied_count, ignored_positive = self._stage_commands( - state, - commands, - now=received_now, - ) - - # Only narrowing transitions leave the durable feed snapshot. - # Inactive kill and LIVE mode never clear a local latch here. - # Apply every reduction before exposing any positive capital from - # the same page. - for command in commands: - if ( - command.envelope.body_schema == KILL_STATE_SCHEMA - and command.envelope.body["active"] is True - ): - self._kill_handler(command) - elif ( - command.envelope.body_schema == DESIRED_MODE_SCHEMA - and command.envelope.body["mode"] != "LIVE" - ): - self._mode_handler(command) - - # Capital acceptance is a local ceiling only. Replays caused by a - # crash before cursor persistence are exact-event idempotent. - for command in commands: - if ( - command.envelope.body_schema == CAPITAL_ENVELOPE_SCHEMA - and command.authority_current - ): - self._capital_adapter.accept_signed_envelope( - command.envelope.wrapper, - ledger_event_digest=command.event_digest, - ledger_global_sequence=command.global_sequence, - ) - - staged["cursor"] = { - "sequence": page["next_sequence"], - "digest": page["next_digest"], - } - staged["required_action"] = page["required_action"] - commit_now = self._now() - if ignored_positive: - staged["status"] = "FAIL_CLOSED" - staged["reason"] = ( - "expired or future positive authority was ignored" - ) - self._fail_closed_handler(staged["reason"]) - submission_allowed = False - elif page["has_more"] is True: - staged["status"] = "CATCHING_UP" - staged["reason"] = "verified command backlog remains" - self._fail_closed_handler(staged["reason"]) - submission_allowed = False - else: - expected_action = self._state_action( - staged, - now=commit_now, - ) - submission_allowed = ( - expected_action == "APPLY_SIGNED_CONTROLS" - ) - staged["status"] = ( - "READY" if submission_allowed else "FAIL_CLOSED" - ) - staged["reason"] = ( - "signed controls verified and cursor synchronized" - if submission_allowed - else f"local controls require {expected_action}" - ) - if not submission_allowed: - self._fail_closed_handler(staged["reason"]) - staged["updated_at"] = _format_utc(commit_now) - self._persist_state( - staged, - expected_cursor=self._cursor(state), - ) - post_commit_now = self._now() - if ( - submission_allowed - and self._state_action(staged, now=post_commit_now) - != "APPLY_SIGNED_CONTROLS" - ): - downgraded = deepcopy(staged) - downgraded["status"] = "FAIL_CLOSED" - downgraded["reason"] = ( - "positive authority expired during state commit" - ) - downgraded["updated_at"] = _format_utc(post_commit_now) - self._fail_closed_handler(downgraded["reason"]) - self._persist_state( - downgraded, - expected_cursor=self._cursor(staged), - ) - staged = downgraded - submission_allowed = False - except Exception as exc: - try: - failure_now = self._now() - except Exception: - failure_now = now - return self._fail_closed( - state=state, - reason=f"command page rejected:{type(exc).__name__}:{exc}", - now=failure_now, - ) - - next_sequence, next_digest = self._cursor(staged) - return CommandFeedPollResult( - page_accepted=True, - cursor_sequence=next_sequence, - cursor_digest=next_digest, - commands_applied=applied_count, - required_action=page["required_action"], - submission_allowed=submission_allowed, - reason=str(staged["reason"]), - ) - - -__all__ = [ - "CELL_ID", - "CommandFeedError", - "CommandFeedPollResult", - "CommandFeedResponse", - "CoreCommandFeedConsumer", - "DESIRED_MODE_SCHEMA", - "KILL_STATE_SCHEMA", - "PAGE_SCHEMA", - "STATE_EVENT_KIND", - "STATE_SCHEMA", - "VerifiedFeedCommand", - "ZERO_DIGEST", -] diff --git a/live_firewall/dumbmoney_execution_cycle.py b/live_firewall/dumbmoney_execution_cycle.py deleted file mode 100644 index 58847efd..00000000 --- a/live_firewall/dumbmoney_execution_cycle.py +++ /dev/null @@ -1,73 +0,0 @@ -"""Sealed execution-cycle boundary with no order-submission capability.""" - -from __future__ import annotations - -import re -from collections.abc import Mapping -from typing import Any - -from live_firewall.dumbmoney_capital import CapitalEnvelopeAdapter -from live_firewall.dumbmoney_command_feed import CoreCommandFeedConsumer - - -EXECUTION_CYCLE_SCHEMA = "dummy.dumbmoney-execution-cycle.v1" -_SHA256_RE = re.compile(r"^[0-9a-f]{64}$") -_BROKER_TRUTH_FIELDS = { - "schema", - "venue", - "account_hash", - "subaccount_number", - "observed_at", - "broker_snapshot_sha256", - "flat_book_observed", - "total_exposure_cents", - "open_order_count", - "market_exposure_cents", - "correlated_exposure_cents", - "unresolved_open_orders", - "unresolved_positions", -} - - -class SealedDisabledExecutionCycle: - """Exercise the execution boundary without owning a broker write sink. - - This object deliberately accepts no broker client, signing key, or callback. - It proves the production service is wired through the exact execution-cycle - interface while remaining structurally unable to submit an order. - """ - - submission_capable = False - deployment_gate = "ATTENDED_LIVE_CANARY_REQUIRED" - - def __call__( - self, - *, - capital_adapter: CapitalEnvelopeAdapter, - command_feed: CoreCommandFeedConsumer, - broker_snapshot: Mapping[str, Any], - ) -> Mapping[str, Any]: - del capital_adapter, command_feed - if ( - not isinstance(broker_snapshot, Mapping) - or set(broker_snapshot) != _BROKER_TRUTH_FIELDS - or broker_snapshot.get("schema") - != "dummy.kalshi-broker-truth.v1" - ): - raise ValueError("broker truth snapshot fields mismatch") - digest = broker_snapshot.get("broker_snapshot_sha256") - if not isinstance(digest, str) or not _SHA256_RE.fullmatch(digest): - raise ValueError("broker truth snapshot digest is invalid") - return { - "schema": EXECUTION_CYCLE_SCHEMA, - "status": "BLOCKED", - "broker_contacted": False, - "orders_submitted": 0, - "broker_snapshot_sha256": digest, - } - - -__all__ = [ - "EXECUTION_CYCLE_SCHEMA", - "SealedDisabledExecutionCycle", -] diff --git a/live_firewall/dumbmoney_journal_anchor.py b/live_firewall/dumbmoney_journal_anchor.py deleted file mode 100644 index 227e9b88..00000000 --- a/live_firewall/dumbmoney_journal_anchor.py +++ /dev/null @@ -1,638 +0,0 @@ -"""Core-backed rollback detection for Dummy's venue-local state stores.""" - -from __future__ import annotations - -import base64 -import hashlib -import json -import math -import re -import secrets -from collections.abc import Callable, Mapping -from dataclasses import dataclass -from datetime import datetime, timedelta, timezone -from typing import Any, Protocol, cast - -from cryptography.exceptions import InvalidSignature -from cryptography.hazmat.primitives.asymmetric.ed25519 import ( - Ed25519PublicKey, -) - -from live_firewall.dumbmoney_capital import verify_signed_envelope -from live_firewall.operational_journal import canonical_json, sha256_json - - -CELL_ID = "dummy_kalshi" -ANCHOR_REQUEST_SCHEMA = "dumbmoney.cell-journal-anchor-request.v1" -ANCHOR_RESPONSE_SCHEMA = "dumbmoney.cell-journal-anchor-response.v1" -ANCHOR_CHECKPOINT_SCHEMA = "dumbmoney.cell-journal-anchor-checkpoint.v1" -ANCHOR_BODY_SCHEMA = "dumbmoney.cell-journal-head-anchor.v1" -LEDGER_PROOF_SCHEMA = "dumbmoney.ledger-event-proof.v1" -CORE_SOURCE_ID = "dumbmoney-core" -MAXIMUM_RESPONSE_BYTES = 524_288 -ZERO_DIGEST = "0" * 64 - -_SHA256_RE = re.compile(r"^[0-9a-f]{64}$") -_IDENTIFIER_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$") -_RFC3339_UTC_RE = re.compile( - r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,6})?Z$" -) -_RESPONSE_FIELDS = { - "schema", - "cell_id", - "request_nonce", - "observed_at", - "reused", - "anchor_envelope", - "ledger_proof", - "checkpoint", - "checkpoint_signature", -} -_CHECKPOINT_FIELDS = { - "schema", - "cell_id", - "request_nonce", - "account_hash", - "journal_name", - "journal_schema", - "journal_stream_id", - "journal_sequence", - "journal_head_sha256", - "anchor_body_digest", - "anchor_event_digest", - "reused", - "observed_at", -} -_SIGNATURE_FIELDS = {"algorithm", "signer_key_id", "signature"} -_ANCHOR_BODY_FIELDS = { - "schema", - "anchor_id", - "venue", - "account_hash", - "journal_name", - "journal_schema", - "journal_stream_id", - "journal_sequence", - "journal_head_sha256", - "previous_anchor_body_digest", - "anchored_at", -} -_LEDGER_PROOF_FIELDS = { - "schema", - "global_sequence", - "event_id", - "source_id", - "source_sequence", - "signer_key_id", - "nonce", - "event_schema", - "observed_at", - "received_at", - "correlation_id", - "causation_id", - "payload_digest", - "previous_source_digest", - "previous_global_digest", - "event_digest", -} - - -class JournalAnchorError(RuntimeError): - """A Core anchor, signature, or monotonicity check failed closed.""" - - -@dataclass(frozen=True) -class JournalAnchorResponse: - status_code: int - body: bytes - - -class JournalAnchorTransport(Protocol): - def __call__( - self, - path: str, - headers: Mapping[str, str], - body: bytes, - ) -> JournalAnchorResponse: ... - - -@dataclass(frozen=True) -class VerifiedJournalAnchor: - journal_name: str - journal_sequence: int - journal_head_sha256: str - anchor_body_digest: str - anchor_event_digest: str - reused: bool - observed_at: str - - -def _utc_now() -> datetime: - return datetime.now(timezone.utc) - - -def _parse_utc(value: Any, *, field: str) -> datetime: - if not isinstance(value, str) or not _RFC3339_UTC_RE.fullmatch(value): - raise JournalAnchorError( - f"{field} must be canonical RFC3339 UTC" - ) - return datetime.fromisoformat(value[:-1] + "+00:00").astimezone( - timezone.utc - ) - - -def _digest(value: Any, *, field: str) -> str: - if not isinstance(value, str) or not _SHA256_RE.fullmatch(value): - raise JournalAnchorError(f"{field} must be a lowercase sha256") - return value - - -def _identifier(value: Any, *, field: str) -> str: - if not isinstance(value, str) or not _IDENTIFIER_RE.fullmatch(value): - raise JournalAnchorError(f"{field} must be a canonical identifier") - return value - - -def _integer(value: Any, *, field: str, minimum: int = 0) -> int: - if isinstance(value, bool) or not isinstance(value, int) or value < minimum: - raise JournalAnchorError( - f"{field} must be an integer >= {minimum}" - ) - return value - - -def _strict_json(body: bytes) -> dict[str, Any]: - if not isinstance(body, bytes) or len(body) > MAXIMUM_RESPONSE_BYTES: - raise JournalAnchorError("Core anchor response size is invalid") - - def pairs(values: list[tuple[str, Any]]) -> dict[str, Any]: - result: dict[str, Any] = {} - for key, value in values: - if key in result: - raise JournalAnchorError( - "Core anchor response contains duplicate keys" - ) - result[key] = value - return result - - def constant(token: str) -> None: - raise JournalAnchorError( - f"Core anchor response contains non-finite value {token}" - ) - - def finite_float(token: str) -> float: - value = float(token) - if not math.isfinite(value): - constant(token) - return value - - try: - decoded = body.decode("utf-8", errors="strict") - value = json.loads( - decoded, - object_pairs_hook=pairs, - parse_constant=constant, - parse_float=finite_float, - ) - except JournalAnchorError: - raise - except (UnicodeDecodeError, json.JSONDecodeError) as exc: - raise JournalAnchorError( - "Core anchor response is not strict UTF-8 JSON" - ) from exc - if not isinstance(value, dict): - raise JournalAnchorError("Core anchor response must be an object") - return cast(dict[str, Any], value) - - -def _decode_signature(value: Any) -> bytes: - if ( - not isinstance(value, str) - or not value - or "=" in value - or re.search(r"[^A-Za-z0-9_-]", value) - ): - raise JournalAnchorError("anchor checkpoint signature is invalid") - try: - decoded = base64.urlsafe_b64decode( - value + "=" * (-len(value) % 4) - ) - except Exception as exc: - raise JournalAnchorError( - "anchor checkpoint signature is invalid" - ) from exc - if ( - len(decoded) != 64 - or base64.urlsafe_b64encode(decoded) - .decode("ascii") - .rstrip("=") - != value - ): - raise JournalAnchorError( - "anchor checkpoint signature encoding is invalid" - ) - return decoded - - -class CoreJournalAnchorClient: - """Publish exact local heads and verify Core's durable signed receipt.""" - - def __init__( - self, - *, - transport: JournalAnchorTransport, - cell_token_provider: Callable[[], str], - trusted_core_public_keys: Mapping[str, bytes | Ed25519PublicKey], - expected_account_hash: str, - request_nonce_fn: Callable[[], str] = lambda: secrets.token_hex(32), - now_fn: Callable[[], datetime] = _utc_now, - ) -> None: - if not trusted_core_public_keys: - raise ValueError("trusted Core public keys are required") - self._transport = transport - self._cell_token_provider = cell_token_provider - self._trusted_core_public_keys = dict(trusted_core_public_keys) - self._expected_account_hash = _digest( - expected_account_hash, - field="expected_account_hash", - ) - self._request_nonce_fn = request_nonce_fn - self._now_fn = now_fn - self._last_nonce: str | None = None - - def stream_id(self, journal_name: str) -> str: - normalized = _identifier(journal_name, field="journal_name") - return sha256_json( - { - "schema": "dummy.journal-anchor-stream.v1", - "cell_id": CELL_ID, - "account_hash": self._expected_account_hash, - "journal_name": normalized, - } - ) - - def _verify_checkpoint( - self, - checkpoint: Any, - signature: Any, - ) -> dict[str, Any]: - if not isinstance(checkpoint, dict) or set(checkpoint) != ( - _CHECKPOINT_FIELDS - ): - raise JournalAnchorError( - "Core anchor checkpoint fields mismatch" - ) - if not isinstance(signature, dict) or set(signature) != ( - _SIGNATURE_FIELDS - ): - raise JournalAnchorError( - "Core anchor checkpoint signature fields mismatch" - ) - if signature["algorithm"] != "Ed25519": - raise JournalAnchorError( - "Core anchor checkpoint algorithm mismatch" - ) - signer = _digest( - signature["signer_key_id"], - field="checkpoint signer_key_id", - ) - key = self._trusted_core_public_keys.get(signer) - if key is None: - raise JournalAnchorError( - "Core anchor checkpoint signer is not pinned" - ) - raw_key = ( - key.public_bytes_raw() - if isinstance(key, Ed25519PublicKey) - else bytes(key) - ) - if len(raw_key) != 32 or hashlib.sha256(raw_key).hexdigest() != signer: - raise JournalAnchorError( - "Core anchor checkpoint key identity mismatch" - ) - try: - Ed25519PublicKey.from_public_bytes(raw_key).verify( - _decode_signature(signature["signature"]), - canonical_json(checkpoint).encode("utf-8"), - ) - except (InvalidSignature, ValueError) as exc: - raise JournalAnchorError( - "Core anchor checkpoint signature is invalid" - ) from exc - return cast(dict[str, Any], checkpoint) - - @staticmethod - def _verify_ledger_proof( - proof_raw: Any, - *, - signed: Any, - observed_at: datetime, - ) -> dict[str, Any]: - if not isinstance(proof_raw, dict): - raise JournalAnchorError("anchor ledger proof must be an object") - proof = json.loads(canonical_json(proof_raw)) - if ( - set(proof) != _LEDGER_PROOF_FIELDS - or proof.get("schema") != LEDGER_PROOF_SCHEMA - ): - raise JournalAnchorError("anchor ledger proof fields mismatch") - sequence = _integer( - proof["global_sequence"], - field="ledger proof global_sequence", - minimum=1, - ) - source_sequence = _integer( - proof["source_sequence"], - field="ledger proof source_sequence", - minimum=1, - ) - received_at = _parse_utc( - proof["received_at"], - field="ledger proof received_at", - ) - record_observed = _parse_utc( - proof["observed_at"], - field="ledger proof observed_at", - ) - if received_at > observed_at: - raise JournalAnchorError( - "anchor ledger proof postdates the checkpoint" - ) - if record_observed != max(received_at, signed.not_before): - raise JournalAnchorError( - "anchor ledger proof observation semantics differ" - ) - previous_global = _digest( - proof["previous_global_digest"], - field="ledger proof previous_global_digest", - ) - previous_source = _digest( - proof["previous_source_digest"], - field="ledger proof previous_source_digest", - ) - if (sequence == 1) != (previous_global == ZERO_DIGEST): - raise JournalAnchorError( - "anchor ledger proof global predecessor is invalid" - ) - if (source_sequence == 1) != (previous_source == ZERO_DIGEST): - raise JournalAnchorError( - "anchor ledger proof source predecessor is invalid" - ) - wrapper = signed.wrapper - expected = { - "event_id": signed.event_id, - "source_id": signed.source_id, - "source_sequence": signed.source_sequence, - "signer_key_id": signed.signer_key_id, - "nonce": signed.nonce, - "event_schema": signed.body_schema, - "correlation_id": wrapper["correlation_id"], - "causation_id": wrapper["causation_id"], - "payload_digest": wrapper["body_digest"], - } - for field, expected_value in expected.items(): - if proof.get(field) != expected_value: - raise JournalAnchorError( - f"anchor ledger proof {field} differs from envelope" - ) - event_digest = _digest( - proof["event_digest"], - field="ledger proof event_digest", - ) - event_material = { - key: value - for key, value in proof.items() - if key not in {"schema", "event_digest"} - } - if sha256_json(event_material) != event_digest: - raise JournalAnchorError( - "anchor ledger proof digest is invalid" - ) - return cast(dict[str, Any], proof) - - def anchor( - self, - *, - journal_name: str, - journal_schema: str, - journal_sequence: int, - journal_head_sha256: str, - ) -> VerifiedJournalAnchor: - name = _identifier(journal_name, field="journal_name") - schema = _identifier(journal_schema, field="journal_schema") - sequence = _integer( - journal_sequence, - field="journal_sequence", - ) - head = _digest( - journal_head_sha256, - field="journal_head_sha256", - ) - if (sequence == 0) != (head == ZERO_DIGEST): - raise JournalAnchorError( - "journal sequence zero must exactly bind the zero head" - ) - stream_id = self.stream_id(name) - nonce = _digest( - self._request_nonce_fn(), - field="request_nonce", - ) - if nonce == self._last_nonce: - raise JournalAnchorError( - "journal anchor nonce generator repeated a nonce" - ) - self._last_nonce = nonce - request = { - "schema": ANCHOR_REQUEST_SCHEMA, - "cell_id": CELL_ID, - "account_hash": self._expected_account_hash, - "journal_name": name, - "journal_schema": schema, - "journal_stream_id": stream_id, - "journal_sequence": sequence, - "journal_head_sha256": head, - "request_nonce": nonce, - } - token = self._cell_token_provider() - if ( - not isinstance(token, str) - or not token - or token != token.strip() - or any(character.isspace() for character in token) - ): - raise JournalAnchorError( - "cell token is not a canonical secret" - ) - try: - response = self._transport( - f"/v1/cells/{CELL_ID}/journal-heads:anchor", - { - "Authorization": f"Bearer {token}", - "Content-Type": "application/json", - }, - canonical_json(request).encode("utf-8"), - ) - except Exception as exc: - raise JournalAnchorError( - f"journal anchor transport failed:{type(exc).__name__}" - ) from exc - finally: - token = "" - if ( - not isinstance(response, JournalAnchorResponse) - or response.status_code != 200 - ): - raise JournalAnchorError( - "Core rejected the journal head anchor" - ) - payload = _strict_json(response.body) - if ( - set(payload) != _RESPONSE_FIELDS - or payload.get("schema") != ANCHOR_RESPONSE_SCHEMA - or payload.get("cell_id") != CELL_ID - or payload.get("request_nonce") != nonce - or not isinstance(payload.get("reused"), bool) - ): - raise JournalAnchorError( - "Core anchor response fields or identity mismatch" - ) - checkpoint = self._verify_checkpoint( - payload["checkpoint"], - payload["checkpoint_signature"], - ) - observed_at = _parse_utc( - payload["observed_at"], - field="anchor response observed_at", - ) - now = self._now_fn() - if now.tzinfo is None or now.utcoffset() is None: - raise JournalAnchorError( - "journal anchor clock must be timezone-aware" - ) - now = now.astimezone(timezone.utc) - if ( - observed_at > now + timedelta(seconds=5) - or now - observed_at > timedelta(seconds=30) - ): - raise JournalAnchorError( - "Core anchor response is not current" - ) - expected_checkpoint = { - "schema": ANCHOR_CHECKPOINT_SCHEMA, - "cell_id": CELL_ID, - "request_nonce": nonce, - "account_hash": self._expected_account_hash, - "journal_name": name, - "journal_schema": schema, - "journal_stream_id": stream_id, - "journal_sequence": sequence, - "journal_head_sha256": head, - "anchor_body_digest": checkpoint["anchor_body_digest"], - "anchor_event_digest": checkpoint["anchor_event_digest"], - "reused": payload["reused"], - "observed_at": payload["observed_at"], - } - if checkpoint != expected_checkpoint: - raise JournalAnchorError( - "Core anchor checkpoint differs from the request" - ) - try: - signed = verify_signed_envelope( - payload["anchor_envelope"], - trusted_public_keys=self._trusted_core_public_keys, - expected_body_schema=ANCHOR_BODY_SCHEMA, - max_ttl=timedelta(seconds=120), - require_active=False, - ) - except (TypeError, ValueError) as exc: - raise JournalAnchorError( - "Core journal anchor envelope is invalid" - ) from exc - if signed.source_id != CORE_SOURCE_ID: - raise JournalAnchorError( - "journal anchor source is not DumbMoney Core" - ) - body = signed.body - if set(body) != _ANCHOR_BODY_FIELDS: - raise JournalAnchorError( - "journal anchor body fields mismatch" - ) - anchored_at = _parse_utc( - body["anchored_at"], - field="anchor body anchored_at", - ) - if ( - body.get("venue") != CELL_ID - or body.get("account_hash") != self._expected_account_hash - or body.get("journal_name") != name - or body.get("journal_schema") != schema - or body.get("journal_stream_id") != stream_id - or body.get("journal_sequence") != sequence - or body.get("journal_head_sha256") != head - or anchored_at > observed_at - ): - raise JournalAnchorError( - "journal anchor body differs from the local head" - ) - previous = _digest( - body["previous_anchor_body_digest"], - field="previous_anchor_body_digest", - ) - expected_anchor_id = sha256_json( - { - "schema": ANCHOR_BODY_SCHEMA, - "venue": CELL_ID, - "account_hash": self._expected_account_hash, - "journal_name": name, - "journal_schema": schema, - "journal_stream_id": stream_id, - "journal_sequence": sequence, - "journal_head_sha256": head, - "previous_anchor_body_digest": previous, - } - ) - if body.get("anchor_id") != expected_anchor_id: - raise JournalAnchorError("journal anchor identity is invalid") - proof = self._verify_ledger_proof( - payload["ledger_proof"], - signed=signed, - observed_at=observed_at, - ) - body_digest = _digest( - checkpoint["anchor_body_digest"], - field="checkpoint anchor_body_digest", - ) - event_digest = _digest( - checkpoint["anchor_event_digest"], - field="checkpoint anchor_event_digest", - ) - if ( - body_digest != signed.wrapper["body_digest"] - or body_digest != proof["payload_digest"] - or event_digest != proof["event_digest"] - ): - raise JournalAnchorError( - "journal anchor checkpoint proof binding is invalid" - ) - return VerifiedJournalAnchor( - journal_name=name, - journal_sequence=sequence, - journal_head_sha256=head, - anchor_body_digest=body_digest, - anchor_event_digest=event_digest, - reused=bool(payload["reused"]), - observed_at=cast(str, payload["observed_at"]), - ) - - -__all__ = [ - "ANCHOR_BODY_SCHEMA", - "ANCHOR_CHECKPOINT_SCHEMA", - "ANCHOR_REQUEST_SCHEMA", - "ANCHOR_RESPONSE_SCHEMA", - "CoreJournalAnchorClient", - "JournalAnchorError", - "JournalAnchorResponse", - "JournalAnchorTransport", - "VerifiedJournalAnchor", -] diff --git a/live_firewall/dumbmoney_lineage.py b/live_firewall/dumbmoney_lineage.py deleted file mode 100644 index f16ba4fd..00000000 --- a/live_firewall/dumbmoney_lineage.py +++ /dev/null @@ -1,1323 +0,0 @@ -"""Authenticated Core resolver for Dummy's singleton live lineage. - -Capital is an upper bound, not evidence that the named strategy, passport, or -promotion exists. This module resolves the exact passport and promotion -digests through DumbMoney Core's loopback-only cell endpoint and verifies: - -* a fresh, nonce-bound Core checkpoint; -* the original ledger proof and signed envelope; -* disjoint Core, research, and promoter signing roles; and -* the complete strategy/passport/promotion/instrument/capital relationship. - -There is deliberately no HTTP client or retry loop here. A sealed local -runner injects one loopback GET transport and a Windows-credential-backed cell -token provider. -""" -from __future__ import annotations - -import base64 -import hashlib -import json -import re -import secrets -import threading -from collections.abc import Callable, Mapping -from dataclasses import dataclass -from datetime import datetime, timedelta, timezone -from typing import Any, Protocol, cast -from urllib.parse import urlencode - -from cryptography.exceptions import InvalidSignature -from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey - -from live_firewall.dumbmoney_capital import ( - VerifiedCapitalEnvelope, - VerifiedSignedEnvelope, - verify_signed_envelope, -) -from live_firewall.operational_journal import canonical_json, sha256_json - - -CELL_ID = "dummy_kalshi" -ALPHA_PASSPORT_SCHEMA = "dumbmoney.alpha_passport.v1" -PROMOTION_CERTIFICATE_SCHEMA = "dumbmoney.promotion-certificate.v1" -CONTRACT_RESOLUTION_SCHEMA = "dumbmoney.cell-contract-resolution.v1" -CONTRACT_RESOLUTION_CHECKPOINT_SCHEMA = ( - "dumbmoney.cell-contract-resolution-checkpoint.v1" -) -LEDGER_PROOF_SCHEMA = "dumbmoney.ledger-event-proof.v1" -LIVE_PROMOTION_STAGES = frozenset( - {"EXPLORATORY_LIVE", "AGGRESSIVE_BOUNDED"} -) -EVIDENCE_CLASSES = frozenset( - {"SYNTHETIC", "REPLAY", "BACKTEST", "PAPER", "FORWARD", "REALIZED"} -) -ZERO_DIGEST = "0" * 64 - -_SHA256_RE = re.compile(r"^[0-9a-f]{64}$") -_IDENTIFIER_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$") -_RFC3339_UTC_RE = re.compile( - r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,6})?Z$" -) -_RESPONSE_FIELDS = { - "schema", - "cell_id", - "request_nonce", - "requested_body_digest", - "capital_envelope_digest", - "fencing_generation", - "observed_at", - "contract_schema", - "transport_window_current", - "body_window_current", - "eligible_live_input", - "authority_state", - "ledger_proof", - "envelope", - "checkpoint", - "checkpoint_signature", -} -_CHECKPOINT_FIELDS = _RESPONSE_FIELDS - { - "checkpoint", - "checkpoint_signature", -} -_SIGNATURE_FIELDS = {"algorithm", "signer_key_id", "signature"} -_LEDGER_PROOF_FIELDS = { - "schema", - "global_sequence", - "event_id", - "source_id", - "source_sequence", - "signer_key_id", - "nonce", - "event_schema", - "observed_at", - "received_at", - "correlation_id", - "causation_id", - "payload_digest", - "previous_source_digest", - "previous_global_digest", - "event_digest", -} -_PASSPORT_FIELDS = { - "schema", - "passport_id", - "strategy_lineage_id", - "venue", - "strategy_hash", - "artifact_hashes", - "evidence_verdict_hashes", - "intended_instruments", - "maximum_loss_cents", - "evidence_class", - "created_at", - "expires_at", -} -_PROMOTION_FIELDS = { - "schema", - "certificate_id", - "passport_digest", - "verdict_digests", - "stage", - "venue", - "instruments", - "maximum_loss_cents", - "rollback_triggers", - "policy_epoch", - "not_before", - "expires_at", -} -AUTHORITY_STATE_SCHEMA = "dumbmoney.cell-authority-state.v1" -_AUTHORITY_STATE_FIELDS = { - "schema", - "evaluated_at", - "authority_valid_until", - "policy_epoch", - "mandate_id", - "mandate_event_digest", - "kill_clear", - "kill_generation", - "kill_event_digest", - "desired_mode", - "desired_mode_revision", - "desired_mode_event_digest", - "capital_envelope_digest", - "capital_event_digest", - "fencing_generation", - "strategy_hash", - "passport_digest", - "passport_event_digest", - "promotion_digest", - "promotion_event_digest", - "verdicts", - "ledger_head_sequence", - "ledger_head_digest", -} -_AUTHORITY_VERDICT_FIELDS = { - "verdict_digest", - "verdict_event_digest", - "verdict_id", - "court", - "decision", - "signer_key_id", - "evaluated_at", - "expires_at", - "transport_expires_at", -} -_VERDICT_COURTS = frozenset( - {"integrity", "statistics", "economics", "adversarial_operations"} -) - - -class LineageResolutionError(RuntimeError): - """A resolver, provenance, or relationship failure that removes authority.""" - - -@dataclass(frozen=True) -class ContractResolutionResponse: - """One injected loopback GET response.""" - - status_code: int - body: bytes - - -class ContractResolutionTransport(Protocol): - def __call__( - self, - path: str, - headers: Mapping[str, str], - ) -> ContractResolutionResponse: ... - - -@dataclass(frozen=True) -class VerifiedLineageBinding: - """Exact authenticated lineage pinned to one current capital fence.""" - - strategy_hash: str - passport_hash: str - promotion_hash: str - authorized_instrument: str - maximum_loss_cents: int - policy_epoch: int - capital_envelope_id: str - capital_event_id: str - capital_body_digest: str - capital_fencing_generation: int - passport_event_id: str - promotion_event_id: str - passport_signer_key_id: str - promotion_signer_key_id: str - expires_at: str - passport_resolution_sha256: str - promotion_resolution_sha256: str - authority_state_sha256: str - authority_kill_generation: int - authority_desired_mode_revision: int - authority_ledger_head_sequence: int - authority_ledger_head_digest: str - authority_valid_until: str - - def evidence(self) -> dict[str, Any]: - return { - "strategy_hash": self.strategy_hash, - "passport_hash": self.passport_hash, - "promotion_hash": self.promotion_hash, - "authorized_instrument": self.authorized_instrument, - "maximum_loss_cents": self.maximum_loss_cents, - "policy_epoch": self.policy_epoch, - "capital_envelope_id": self.capital_envelope_id, - "capital_event_id": self.capital_event_id, - "capital_body_digest": self.capital_body_digest, - "capital_fencing_generation": self.capital_fencing_generation, - "passport_event_id": self.passport_event_id, - "promotion_event_id": self.promotion_event_id, - "passport_signer_key_id": self.passport_signer_key_id, - "promotion_signer_key_id": self.promotion_signer_key_id, - "expires_at": self.expires_at, - "passport_resolution_sha256": self.passport_resolution_sha256, - "promotion_resolution_sha256": self.promotion_resolution_sha256, - "authority_state_sha256": self.authority_state_sha256, - "authority_kill_generation": self.authority_kill_generation, - "authority_desired_mode_revision": ( - self.authority_desired_mode_revision - ), - "authority_ledger_head_sequence": ( - self.authority_ledger_head_sequence - ), - "authority_ledger_head_digest": self.authority_ledger_head_digest, - "authority_valid_until": self.authority_valid_until, - } - - -@dataclass(frozen=True) -class _ResolvedContract: - response: dict[str, Any] - signed: VerifiedSignedEnvelope - body_not_before: datetime - body_expires_at: datetime - authority_state: dict[str, Any] - - -def _utc_now() -> datetime: - return datetime.now(timezone.utc) - - -def _parse_utc(value: Any, *, field: str) -> datetime: - if not isinstance(value, str) or not _RFC3339_UTC_RE.fullmatch(value): - raise LineageResolutionError(f"{field} must be canonical RFC3339 UTC") - parsed = datetime.fromisoformat(value[:-1] + "+00:00") - return parsed.astimezone(timezone.utc) - - -def _format_utc(value: datetime) -> str: - return value.astimezone(timezone.utc).isoformat().replace("+00:00", "Z") - - -def _digest(value: Any, *, field: str) -> str: - if not isinstance(value, str) or not _SHA256_RE.fullmatch(value): - raise LineageResolutionError(f"{field} must be a lowercase sha256") - return value - - -def _identifier(value: Any, *, field: str) -> str: - if not isinstance(value, str) or not _IDENTIFIER_RE.fullmatch(value): - raise LineageResolutionError(f"{field} must be a canonical identifier") - return value - - -def _positive_int(value: Any, *, field: str) -> int: - if isinstance(value, bool) or not isinstance(value, int) or value < 1: - raise LineageResolutionError(f"{field} must be a positive integer") - return value - - -def _sorted_hashes( - value: Any, - *, - field: str, - allow_empty: bool = False, -) -> tuple[str, ...]: - if not isinstance(value, list) or (not value and not allow_empty): - qualifier = "an array" if allow_empty else "a nonempty array" - raise LineageResolutionError(f"{field} must be {qualifier}") - result = tuple(_digest(item, field=f"{field}[]") for item in value) - if result != tuple(sorted(set(result))): - raise LineageResolutionError(f"{field} must be sorted and unique") - return result - - -def _sorted_identifiers(value: Any, *, field: str) -> tuple[str, ...]: - if not isinstance(value, list) or not value: - raise LineageResolutionError(f"{field} must be a nonempty array") - result = tuple(_identifier(item, field=f"{field}[]") for item in value) - if result != tuple(sorted(set(result))): - raise LineageResolutionError(f"{field} must be sorted and unique") - return result - - -def _decode_signature(value: Any) -> bytes: - if ( - not isinstance(value, str) - or not value - or "=" in value - or re.search(r"[^A-Za-z0-9_-]", value) - ): - raise LineageResolutionError("signature must be unpadded base64url") - try: - decoded = base64.urlsafe_b64decode(value + "=" * (-len(value) % 4)) - except Exception as exc: - raise LineageResolutionError("signature is invalid base64url") from exc - if base64.urlsafe_b64encode(decoded).decode("ascii").rstrip("=") != value: - raise LineageResolutionError("signature is not canonical base64url") - return decoded - - -def _keyring( - raw: Mapping[str, bytes | Ed25519PublicKey], - *, - role: str, - maximum_keys: int = 16, -) -> dict[str, bytes]: - if not isinstance(raw, Mapping) or not 1 <= len(raw) <= maximum_keys: - raise ValueError( - f"{role} keyring must contain 1 to {maximum_keys} keys" - ) - result: dict[str, bytes] = {} - for raw_key_id, material in raw.items(): - key_id = _digest(raw_key_id, field=f"{role} key id") - key = ( - material.public_bytes_raw() - if isinstance(material, Ed25519PublicKey) - else bytes(material) - ) - if len(key) != 32 or hashlib.sha256(key).hexdigest() != key_id: - raise ValueError(f"{role} key id does not bind its Ed25519 key") - result[key_id] = key - return result - - -def _strict_json(body: bytes, *, maximum_bytes: int) -> dict[str, Any]: - if not isinstance(body, bytes): - raise LineageResolutionError("contract response body must be bytes") - if not body or len(body) > maximum_bytes: - raise LineageResolutionError("contract response size is invalid") - - def reject_duplicates(pairs: list[tuple[str, Any]]) -> dict[str, Any]: - value: dict[str, Any] = {} - for key, item in pairs: - if key in value: - raise LineageResolutionError( - f"contract response contains duplicate key {key!r}" - ) - value[key] = item - return value - - try: - value = json.loads( - body.decode("utf-8"), - object_pairs_hook=reject_duplicates, - parse_constant=lambda token: (_ for _ in ()).throw( - LineageResolutionError( - f"contract response contains non-finite value {token}" - ) - ), - ) - except (UnicodeDecodeError, json.JSONDecodeError) as exc: - raise LineageResolutionError("contract response is not strict JSON") from exc - if not isinstance(value, dict): - raise LineageResolutionError("contract response must be an object") - return value - - -def _validate_checkpoint( - checkpoint_raw: Any, - signature_raw: Any, - *, - core_keys: Mapping[str, bytes], -) -> dict[str, Any]: - if not isinstance(checkpoint_raw, dict) or not isinstance(signature_raw, dict): - raise LineageResolutionError( - "contract checkpoint and signature must be objects" - ) - checkpoint = json.loads(canonical_json(checkpoint_raw)) - signature = json.loads(canonical_json(signature_raw)) - if ( - set(checkpoint) != _CHECKPOINT_FIELDS - or checkpoint.get("schema") - != CONTRACT_RESOLUTION_CHECKPOINT_SCHEMA - ): - raise LineageResolutionError("contract checkpoint fields mismatch") - if set(signature) != _SIGNATURE_FIELDS: - raise LineageResolutionError("contract checkpoint signature fields mismatch") - if signature["algorithm"] != "Ed25519": - raise LineageResolutionError("contract checkpoint algorithm mismatch") - signer = _digest( - signature["signer_key_id"], - field="contract checkpoint signer_key_id", - ) - public_key = core_keys.get(signer) - if public_key is None: - raise LineageResolutionError("contract checkpoint signer is not pinned Core") - raw_signature = _decode_signature(signature["signature"]) - if len(raw_signature) != 64: - raise LineageResolutionError( - "contract checkpoint signature must be 64 bytes" - ) - try: - Ed25519PublicKey.from_public_bytes(public_key).verify( - raw_signature, - canonical_json(checkpoint).encode("utf-8"), - ) - except (InvalidSignature, ValueError) as exc: - raise LineageResolutionError( - "contract checkpoint signature is invalid" - ) from exc - return cast(dict[str, Any], checkpoint) - - -def _validate_ledger_proof( - proof_raw: Any, - *, - signed: VerifiedSignedEnvelope, - expected_schema: str, - observed_at: datetime, -) -> dict[str, Any]: - if not isinstance(proof_raw, dict): - raise LineageResolutionError("contract ledger proof must be an object") - proof = json.loads(canonical_json(proof_raw)) - if ( - set(proof) != _LEDGER_PROOF_FIELDS - or proof.get("schema") != LEDGER_PROOF_SCHEMA - ): - raise LineageResolutionError("contract ledger proof fields mismatch") - global_sequence = _positive_int( - proof["global_sequence"], - field="ledger global_sequence", - ) - source_sequence = _positive_int( - proof["source_sequence"], - field="ledger source_sequence", - ) - event_id = _digest(proof["event_id"], field="ledger event_id") - event_digest = _digest(proof["event_digest"], field="ledger event_digest") - payload_digest = _digest( - proof["payload_digest"], - field="ledger payload_digest", - ) - previous_source = _digest( - proof["previous_source_digest"], - field="ledger previous_source_digest", - ) - previous_global = _digest( - proof["previous_global_digest"], - field="ledger previous_global_digest", - ) - source_id = _identifier(proof["source_id"], field="ledger source_id") - signer = _digest(proof["signer_key_id"], field="ledger signer_key_id") - nonce = _identifier(proof["nonce"], field="ledger nonce") - event_schema = _identifier(proof["event_schema"], field="ledger event_schema") - correlation = _identifier( - proof["correlation_id"], - field="ledger correlation_id", - ) - causation = proof["causation_id"] - if causation is not None: - causation = _digest(causation, field="ledger causation_id") - record_observed = _parse_utc( - proof["observed_at"], - field="ledger observed_at", - ) - received_at = _parse_utc(proof["received_at"], field="ledger received_at") - if received_at > observed_at: - raise LineageResolutionError( - "ledger proof was received after contract observation" - ) - if record_observed != max(received_at, signed.not_before): - raise LineageResolutionError( - "ledger proof observed_at differs from ingestion semantics" - ) - if (global_sequence == 1) != (previous_global == ZERO_DIGEST): - raise LineageResolutionError("ledger previous_global_digest mismatch") - if (source_sequence == 1) != (previous_source == ZERO_DIGEST): - raise LineageResolutionError("ledger previous_source_digest mismatch") - wrapper = signed.wrapper - duplicated = { - "event_id": (event_id, signed.event_id), - "source_id": (source_id, signed.source_id), - "source_sequence": (source_sequence, signed.source_sequence), - "signer_key_id": (signer, signed.signer_key_id), - "nonce": (nonce, signed.nonce), - "event_schema": (event_schema, expected_schema), - "correlation_id": (correlation, wrapper["correlation_id"]), - "causation_id": (causation, wrapper["causation_id"]), - "payload_digest": (payload_digest, wrapper["body_digest"]), - } - for field, (actual, expected) in duplicated.items(): - if actual != expected: - raise LineageResolutionError( - f"ledger proof {field} differs from contract envelope" - ) - event_material = { - key: item - for key, item in proof.items() - if key not in {"schema", "event_digest"} - } - if sha256_json(event_material) != event_digest: - raise LineageResolutionError( - "ledger proof event_digest does not match event material" - ) - return cast(dict[str, Any], proof) - - -def _validate_authority_state( - raw_state: Any, - *, - capital: VerifiedCapitalEnvelope, - now: datetime, - evaluator_keys: Mapping[str, bytes], - maximum_resolution_age: timedelta, - maximum_future_skew: timedelta, -) -> dict[str, Any]: - """Validate the complete Core-signed authority projection. - - The verdict documents themselves remain Core ledger records; this - projection pins their event identities and requires their signer key IDs - to belong to the sealed evaluator role. The surrounding checkpoint signs - every byte of this state. - """ - if not isinstance(raw_state, dict): - raise LineageResolutionError( - "contract authority_state must be an object" - ) - state = json.loads(canonical_json(raw_state)) - if ( - set(state) != _AUTHORITY_STATE_FIELDS - or state.get("schema") != AUTHORITY_STATE_SCHEMA - ): - raise LineageResolutionError("contract authority_state fields mismatch") - - evaluated_at = _parse_utc( - state["evaluated_at"], - field="authority_state evaluated_at", - ) - valid_until = _parse_utc( - state["authority_valid_until"], - field="authority_state authority_valid_until", - ) - if evaluated_at > now + maximum_future_skew: - raise LineageResolutionError("contract authority_state is future-dated") - if now - evaluated_at > maximum_resolution_age: - raise LineageResolutionError("contract authority_state is stale") - if not evaluated_at < valid_until or not now < valid_until: - raise LineageResolutionError( - "contract authority_state validity window is not current" - ) - if ( - capital.ledger_event_digest is None - or capital.ledger_global_sequence is None - ): - raise LineageResolutionError( - "active capital lacks its authenticated Core ledger binding" - ) - expected = { - "policy_epoch": capital.policy_epoch, - "mandate_id": capital.body["mandate_id"], - "kill_clear": True, - "desired_mode": "LIVE", - "capital_envelope_digest": sha256_json(capital.body), - "capital_event_digest": capital.ledger_event_digest, - "fencing_generation": capital.fencing_generation, - "strategy_hash": capital.strategy_hashes[0], - "passport_digest": capital.passport_hashes[0], - "promotion_digest": capital.promotion_hashes[0], - } - for field, value in expected.items(): - if state.get(field) != value: - raise LineageResolutionError( - f"contract authority_state {field} differs from active authority" - ) - for field in ( - "kill_generation", - "desired_mode_revision", - "ledger_head_sequence", - ): - _positive_int(state[field], field=f"authority_state {field}") - for field in ( - "mandate_event_digest", - "kill_event_digest", - "desired_mode_event_digest", - "capital_event_digest", - "passport_event_digest", - "promotion_event_digest", - "ledger_head_digest", - ): - _digest(state[field], field=f"authority_state {field}") - - capital_sequence = capital.ledger_global_sequence - head_sequence = int(state["ledger_head_sequence"]) - if head_sequence < capital_sequence or ( - head_sequence == capital_sequence - and state["ledger_head_digest"] != capital.ledger_event_digest - ): - raise LineageResolutionError( - "active capital is not continuous with the authority ledger head" - ) - - verdicts = state["verdicts"] - if not isinstance(verdicts, list) or len(verdicts) < 2: - raise LineageResolutionError( - "contract authority_state requires at least two PASS verdicts" - ) - facts: set[tuple[str, str, str, str]] = set() - courts: set[str] = set() - for index, raw_verdict in enumerate(verdicts): - if not isinstance(raw_verdict, dict): - raise LineageResolutionError( - f"authority_state verdict {index} must be an object" - ) - verdict = json.loads(canonical_json(raw_verdict)) - if set(verdict) != _AUTHORITY_VERDICT_FIELDS: - raise LineageResolutionError( - f"authority_state verdict {index} fields mismatch" - ) - verdict_digest = _digest( - verdict["verdict_digest"], - field=f"authority_state verdict {index} digest", - ) - event_digest = _digest( - verdict["verdict_event_digest"], - field=f"authority_state verdict {index} event_digest", - ) - verdict_id = _identifier( - verdict["verdict_id"], - field=f"authority_state verdict {index} id", - ) - court = verdict["court"] - if ( - court not in _VERDICT_COURTS - or verdict["decision"] != "PASS" - ): - raise LineageResolutionError( - "contract authority verdict is not a recognized PASS" - ) - signer = _digest( - verdict["signer_key_id"], - field=f"authority_state verdict {index} signer_key_id", - ) - if signer not in evaluator_keys: - raise LineageResolutionError( - "contract authority verdict signer is not sealed" - ) - verdict_evaluated = _parse_utc( - verdict["evaluated_at"], - field=f"authority_state verdict {index} evaluated_at", - ) - verdict_expires = _parse_utc( - verdict["expires_at"], - field=f"authority_state verdict {index} expires_at", - ) - transport_expires = _parse_utc( - verdict["transport_expires_at"], - field=f"authority_state verdict {index} transport_expires_at", - ) - if ( - verdict_evaluated > now + maximum_future_skew - or not verdict_evaluated < verdict_expires - or not now < verdict_expires - or not now < transport_expires - or valid_until > min(verdict_expires, transport_expires) - ): - raise LineageResolutionError( - "contract authority verdict is stale, future-dated, or expired" - ) - facts.add((verdict_digest, event_digest, verdict_id, court)) - courts.add(court) - if len(facts) != len(verdicts) or len(courts) < 2: - raise LineageResolutionError( - "contract authority verdict facts or courts are not unique" - ) - return cast(dict[str, Any], state) - - -def _validate_passport( - signed: VerifiedSignedEnvelope, - *, - now: datetime, -) -> tuple[datetime, datetime]: - body = signed.body - if set(body) != _PASSPORT_FIELDS: - raise LineageResolutionError("AlphaPassport fields mismatch") - if body["schema"] != ALPHA_PASSPORT_SCHEMA or body["venue"] != CELL_ID: - raise LineageResolutionError("AlphaPassport identity mismatch") - _identifier(body["passport_id"], field="passport_id") - _identifier(body["strategy_lineage_id"], field="strategy_lineage_id") - _digest(body["strategy_hash"], field="passport strategy_hash") - _sorted_hashes(body["artifact_hashes"], field="passport artifact_hashes") - _sorted_hashes( - body["evidence_verdict_hashes"], - field="passport evidence_verdict_hashes", - allow_empty=True, - ) - instruments = _sorted_identifiers( - body["intended_instruments"], - field="passport intended_instruments", - ) - if any( - not item.startswith("event_contract:") - or item.endswith(":") - or "*" in item - for item in instruments - ): - raise LineageResolutionError( - "AlphaPassport contains a noncanonical Dummy instrument" - ) - _positive_int(body["maximum_loss_cents"], field="passport maximum_loss_cents") - if body["evidence_class"] not in EVIDENCE_CLASSES: - raise LineageResolutionError("AlphaPassport evidence_class is unsupported") - starts = _parse_utc(body["created_at"], field="passport created_at") - expires = _parse_utc(body["expires_at"], field="passport expires_at") - if expires <= starts or not starts <= now < expires: - raise LineageResolutionError("AlphaPassport body window is not current") - return starts, expires - - -def _validate_promotion( - signed: VerifiedSignedEnvelope, - *, - now: datetime, -) -> tuple[datetime, datetime]: - body = signed.body - if set(body) != _PROMOTION_FIELDS: - raise LineageResolutionError("PromotionCertificate fields mismatch") - if body["schema"] != PROMOTION_CERTIFICATE_SCHEMA or body["venue"] != CELL_ID: - raise LineageResolutionError("PromotionCertificate identity mismatch") - _identifier(body["certificate_id"], field="certificate_id") - _digest(body["passport_digest"], field="promotion passport_digest") - _sorted_hashes(body["verdict_digests"], field="promotion verdict_digests") - if body["stage"] not in LIVE_PROMOTION_STAGES: - raise LineageResolutionError( - "PromotionCertificate stage is not live-authorizing" - ) - instruments = _sorted_identifiers( - body["instruments"], - field="promotion instruments", - ) - if any( - not item.startswith("event_contract:") - or item.endswith(":") - or "*" in item - for item in instruments - ): - raise LineageResolutionError( - "PromotionCertificate contains a noncanonical Dummy instrument" - ) - _positive_int( - body["maximum_loss_cents"], - field="promotion maximum_loss_cents", - ) - _sorted_identifiers( - body["rollback_triggers"], - field="promotion rollback_triggers", - ) - _positive_int(body["policy_epoch"], field="promotion policy_epoch") - starts = _parse_utc(body["not_before"], field="promotion not_before") - expires = _parse_utc(body["expires_at"], field="promotion expires_at") - if expires <= starts or not starts <= now < expires: - raise LineageResolutionError( - "PromotionCertificate body window is not current" - ) - return starts, expires - - -class CoreAuthorityContractResolver: - """Fetch and authenticate the exact singleton lineage named by capital.""" - - def __init__( - self, - *, - transport: ContractResolutionTransport, - cell_token_provider: Callable[[], str], - trusted_core_public_keys: Mapping[ - str, - bytes | Ed25519PublicKey, - ], - trusted_research_public_keys: Mapping[ - str, - bytes | Ed25519PublicKey, - ], - trusted_promoter_public_keys: Mapping[ - str, - bytes | Ed25519PublicKey, - ], - trusted_evaluator_public_keys: Mapping[ - str, - bytes | Ed25519PublicKey, - ], - now_fn: Callable[[], datetime] | None = None, - request_nonce_fn: Callable[[], str] | None = None, - maximum_response_bytes: int = 1_048_576, - maximum_resolution_age: timedelta = timedelta(seconds=60), - maximum_future_skew: timedelta = timedelta(seconds=5), - ) -> None: - if not callable(transport) or not callable(cell_token_provider): - raise TypeError("resolver transport and token provider must be callable") - if request_nonce_fn is not None and not callable(request_nonce_fn): - raise TypeError("resolver nonce provider must be callable") - if maximum_response_bytes < 1: - raise ValueError("maximum response bytes must be positive") - if maximum_resolution_age <= timedelta(0): - raise ValueError("maximum resolution age must be positive") - if maximum_future_skew < timedelta(0): - raise ValueError("maximum future skew cannot be negative") - core = _keyring(trusted_core_public_keys, role="Core") - research = _keyring(trusted_research_public_keys, role="research") - promoter = _keyring(trusted_promoter_public_keys, role="promoter") - evaluator = _keyring( - trusted_evaluator_public_keys, - role="evaluator", - maximum_keys=32, - ) - if set(core) & set(research) or set(core) & set(promoter): - raise ValueError("Core and contract signing roles must be disjoint") - if set(research) & set(promoter): - raise ValueError("research and promoter signing roles must be disjoint") - if ( - set(evaluator) & set(core) - or set(evaluator) & set(research) - or set(evaluator) & set(promoter) - ): - raise ValueError( - "evaluator and control/contract signing roles must be disjoint" - ) - self._transport = transport - self._cell_token_provider = cell_token_provider - self._core_keys = core - self._research_keys = research - self._promoter_keys = promoter - self._evaluator_keys = evaluator - self._now_fn = now_fn or _utc_now - self._request_nonce_fn = request_nonce_fn or ( - lambda: secrets.token_hex(32) - ) - self._nonce_lock = threading.Lock() - self._last_nonce: str | None = None - self.maximum_response_bytes = maximum_response_bytes - self.maximum_resolution_age = maximum_resolution_age - self.maximum_future_skew = maximum_future_skew - - def _now(self) -> datetime: - now = self._now_fn() - if now.tzinfo is None or now.utcoffset() is None: - raise LineageResolutionError( - "contract resolver clock must be timezone-aware" - ) - return now.astimezone(timezone.utc) - - def _nonce(self) -> str: - try: - nonce = _digest( - self._request_nonce_fn(), - field="contract request_nonce", - ) - except Exception as exc: - raise LineageResolutionError( - "cryptographic contract nonce generation failed" - ) from exc - with self._nonce_lock: - if nonce == self._last_nonce: - raise LineageResolutionError("contract request nonce replay") - self._last_nonce = nonce - return nonce - - def _token(self) -> str: - try: - token = self._cell_token_provider() - except Exception as exc: - raise LineageResolutionError( - "cell bearer retrieval failed closed" - ) from exc - if ( - not isinstance(token, str) - or token != token.strip() - or not 32 <= len(token) <= 4096 - or any(ord(char) < 33 or ord(char) > 126 for char in token) - ): - raise LineageResolutionError("cell bearer is invalid") - return token - - def _resolve( - self, - *, - digest: str, - expected_schema: str, - capital: VerifiedCapitalEnvelope, - ) -> _ResolvedContract: - requested_digest = _digest(digest, field="requested contract digest") - capital_digest = _digest( - sha256_json(capital.body), - field="active capital body digest", - ) - if expected_schema not in { - ALPHA_PASSPORT_SCHEMA, - PROMOTION_CERTIFICATE_SCHEMA, - }: - raise LineageResolutionError("requested contract schema is unsupported") - fence = _positive_int( - capital.fencing_generation, - field="active capital fencing generation", - ) - request_nonce = self._nonce() - query = urlencode( - { - "capital_envelope_digest": capital_digest, - "request_nonce": request_nonce, - } - ) - path = ( - f"/v1/cells/{CELL_ID}/contracts/{requested_digest}?{query}" - ) - try: - response = self._transport( - path, - { - "Accept": "application/json", - "Authorization": f"Bearer {self._token()}", - }, - ) - except Exception as exc: - raise LineageResolutionError( - f"contract transport failed closed:{type(exc).__name__}" - ) from exc - if not isinstance(response, ContractResolutionResponse): - raise LineageResolutionError( - "contract transport returned an unsupported response" - ) - if isinstance(response.status_code, bool) or not isinstance( - response.status_code, - int, - ): - raise LineageResolutionError("contract response status is invalid") - if response.status_code in {401, 403}: - raise LineageResolutionError( - "contract resolution authentication or scope was denied" - ) - if response.status_code != 200: - raise LineageResolutionError( - f"contract resolver returned HTTP {response.status_code}" - ) - payload = _strict_json( - response.body, - maximum_bytes=self.maximum_response_bytes, - ) - now = self._now() - if ( - set(payload) != _RESPONSE_FIELDS - or payload.get("schema") != CONTRACT_RESOLUTION_SCHEMA - ): - raise LineageResolutionError("contract resolution fields mismatch") - checkpoint = _validate_checkpoint( - payload["checkpoint"], - payload["checkpoint_signature"], - core_keys=self._core_keys, - ) - expected_checkpoint = { - key: item - for key, item in payload.items() - if key not in {"schema", "checkpoint", "checkpoint_signature"} - } - expected_checkpoint["schema"] = ( - CONTRACT_RESOLUTION_CHECKPOINT_SCHEMA - ) - if checkpoint != expected_checkpoint: - raise LineageResolutionError( - "signed checkpoint does not bind the full contract resolution" - ) - if payload["cell_id"] != CELL_ID: - raise LineageResolutionError( - "contract resolution targets another venue cell" - ) - if ( - _digest(payload["request_nonce"], field="response request_nonce") - != request_nonce - ): - raise LineageResolutionError("contract response nonce mismatch") - if ( - _digest( - payload["requested_body_digest"], - field="response requested_body_digest", - ) - != requested_digest - ): - raise LineageResolutionError("contract response digest mismatch") - if ( - _digest( - payload["capital_envelope_digest"], - field="response capital_envelope_digest", - ) - != capital_digest - ): - raise LineageResolutionError( - "contract response is not bound to active capital" - ) - if payload["fencing_generation"] != fence or isinstance( - payload["fencing_generation"], - bool, - ): - raise LineageResolutionError( - "contract response is not bound to active capital fence" - ) - if payload["contract_schema"] != expected_schema: - raise LineageResolutionError("contract response schema mismatch") - for field in ( - "transport_window_current", - "body_window_current", - "eligible_live_input", - ): - if not isinstance(payload[field], bool): - raise LineageResolutionError( - f"contract response {field} must be boolean" - ) - observed_at = _parse_utc( - payload["observed_at"], - field="contract observed_at", - ) - if observed_at > now + self.maximum_future_skew: - raise LineageResolutionError( - "contract response observation is future-dated" - ) - if now - observed_at > self.maximum_resolution_age: - raise LineageResolutionError("contract response observation is stale") - envelope = payload["envelope"] - if not isinstance(envelope, dict): - raise LineageResolutionError( - "contract response envelope must be an object" - ) - role_keys = ( - self._research_keys - if expected_schema == ALPHA_PASSPORT_SCHEMA - else self._promoter_keys - ) - try: - signed = verify_signed_envelope( - envelope, - trusted_public_keys=role_keys, - now=now, - expected_body_schema=expected_schema, - ) - except ValueError as exc: - raise LineageResolutionError( - f"resolved signed contract invalid: {exc}" - ) from exc - if signed.wrapper["body_digest"] != requested_digest: - raise LineageResolutionError( - "resolved envelope body digest differs from request" - ) - authority_state = _validate_authority_state( - payload["authority_state"], - capital=capital, - now=now, - evaluator_keys=self._evaluator_keys, - maximum_resolution_age=self.maximum_resolution_age, - maximum_future_skew=self.maximum_future_skew, - ) - if ( - _parse_utc( - authority_state["evaluated_at"], - field="authority_state evaluated_at", - ) - != observed_at - ): - raise LineageResolutionError( - "contract authority_state evaluated_at does not mirror observed_at" - ) - proof = _validate_ledger_proof( - payload["ledger_proof"], - signed=signed, - expected_schema=expected_schema, - observed_at=observed_at, - ) - authority_event_digest = authority_state[ - ( - "promotion_event_digest" - if expected_schema == PROMOTION_CERTIFICATE_SCHEMA - else "passport_event_digest" - ) - ] - if proof["event_digest"] != authority_event_digest: - raise LineageResolutionError( - "contract proof event digest differs from authority_state" - ) - proof_sequence = int(proof["global_sequence"]) - head_sequence = int(authority_state["ledger_head_sequence"]) - if proof_sequence > head_sequence or ( - proof_sequence == head_sequence - and proof["event_digest"] != authority_state["ledger_head_digest"] - ): - raise LineageResolutionError( - "contract proof is not continuous with the authority ledger head" - ) - if expected_schema == ALPHA_PASSPORT_SCHEMA: - body_starts, body_expires = _validate_passport(signed, now=now) - else: - body_starts, body_expires = _validate_promotion(signed, now=now) - transport_current = ( - signed.not_before <= observed_at < signed.expires_at - ) - body_current = body_starts <= observed_at < body_expires - eligible = transport_current and body_current - if expected_schema == PROMOTION_CERTIFICATE_SCHEMA: - eligible = ( - eligible - and signed.body["stage"] in LIVE_PROMOTION_STAGES - ) - if payload["transport_window_current"] is not transport_current: - raise LineageResolutionError( - "contract transport-window projection mismatch" - ) - if payload["body_window_current"] is not body_current: - raise LineageResolutionError( - "contract body-window projection mismatch" - ) - if payload["eligible_live_input"] is not eligible: - raise LineageResolutionError( - "contract live-eligibility projection mismatch" - ) - if not eligible: - raise LineageResolutionError( - "resolved contract is not an eligible current live input" - ) - return _ResolvedContract( - response=json.loads(canonical_json(payload)), - signed=signed, - body_not_before=body_starts, - body_expires_at=body_expires, - authority_state=authority_state, - ) - - def resolve_lineage( - self, - *, - capital: VerifiedCapitalEnvelope, - strategy_hash: str, - passport_hash: str, - promotion_hash: str, - authorized_instrument: str, - expected_binding: Mapping[str, Any] | None = None, - ) -> VerifiedLineageBinding: - """Resolve and bind the exact active singleton lineage.""" - now = self._now() - strategy = _digest(strategy_hash, field="strategy_hash") - passport = _digest(passport_hash, field="passport_hash") - promotion = _digest(promotion_hash, field="promotion_hash") - instrument = _identifier( - authorized_instrument, - field="authorized_instrument", - ) - if ( - capital.venue != CELL_ID - or capital.strategy_hashes != (strategy,) - or capital.passport_hashes != (passport,) - or capital.promotion_hashes != (promotion,) - or instrument not in capital.authorized_instruments - ): - raise LineageResolutionError( - "requested lineage differs from singleton capital authority" - ) - capital_body_digest = sha256_json(capital.body) - promotion_resolution = self._resolve( - digest=promotion, - expected_schema=PROMOTION_CERTIFICATE_SCHEMA, - capital=capital, - ) - passport_resolution = self._resolve( - digest=passport, - expected_schema=ALPHA_PASSPORT_SCHEMA, - capital=capital, - ) - promotion_authority = { - key: item - for key, item in promotion_resolution.authority_state.items() - if key != "evaluated_at" - } - passport_authority = { - key: item - for key, item in passport_resolution.authority_state.items() - if key != "evaluated_at" - } - if promotion_authority != passport_authority: - raise LineageResolutionError( - "promotion and passport were not resolved from one authority state" - ) - promotion_body = promotion_resolution.signed.body - passport_body = passport_resolution.signed.body - if promotion_body["passport_digest"] != passport: - raise LineageResolutionError( - "promotion does not bind the singleton capital passport" - ) - if passport_body["strategy_hash"] != strategy: - raise LineageResolutionError( - "passport does not bind the singleton capital strategy" - ) - if ( - instrument not in passport_body["intended_instruments"] - or instrument not in promotion_body["instruments"] - ): - raise LineageResolutionError( - "instrument is not jointly authorized by lineage" - ) - if promotion_body["policy_epoch"] != capital.policy_epoch: - raise LineageResolutionError( - "promotion and capital policy epochs differ" - ) - lineage_loss = min( - int(passport_body["maximum_loss_cents"]), - int(promotion_body["maximum_loss_cents"]), - ) - if capital.max_order_risk_cents > lineage_loss: - raise LineageResolutionError( - "capital order bound exceeds lineage maximum loss" - ) - expires_at = min( - capital.expires_at, - passport_resolution.signed.expires_at, - passport_resolution.body_expires_at, - promotion_resolution.signed.expires_at, - promotion_resolution.body_expires_at, - _parse_utc( - promotion_authority["authority_valid_until"], - field="authority_state authority_valid_until", - ), - ) - if now >= expires_at: - raise LineageResolutionError( - "authenticated lineage binding is already expired" - ) - binding = VerifiedLineageBinding( - strategy_hash=strategy, - passport_hash=passport, - promotion_hash=promotion, - authorized_instrument=instrument, - maximum_loss_cents=lineage_loss, - policy_epoch=capital.policy_epoch, - capital_envelope_id=capital.envelope_id, - capital_event_id=capital.event_id, - capital_body_digest=capital_body_digest, - capital_fencing_generation=capital.fencing_generation, - passport_event_id=passport_resolution.signed.event_id, - promotion_event_id=promotion_resolution.signed.event_id, - passport_signer_key_id=passport_resolution.signed.signer_key_id, - promotion_signer_key_id=promotion_resolution.signed.signer_key_id, - expires_at=_format_utc(expires_at), - passport_resolution_sha256=sha256_json( - passport_resolution.response - ), - promotion_resolution_sha256=sha256_json( - promotion_resolution.response - ), - authority_state_sha256=sha256_json(promotion_authority), - authority_kill_generation=int( - promotion_authority["kill_generation"] - ), - authority_desired_mode_revision=int( - promotion_authority["desired_mode_revision"] - ), - authority_ledger_head_sequence=int( - promotion_authority["ledger_head_sequence"] - ), - authority_ledger_head_digest=str( - promotion_authority["ledger_head_digest"] - ), - authority_valid_until=str( - promotion_authority["authority_valid_until"] - ), - ) - if expected_binding is not None: - expected = json.loads(canonical_json(dict(expected_binding))) - actual = binding.evidence() - # A fresh resolution necessarily has a new request nonce and - # therefore new page digests. Compare the signed contract/event - # identity and complete authority relationship, not transport - # transcript hashes from the earlier binding pass. - expected.pop("passport_resolution_sha256", None) - expected.pop("promotion_resolution_sha256", None) - actual.pop("passport_resolution_sha256", None) - actual.pop("promotion_resolution_sha256", None) - if expected != actual: - raise LineageResolutionError( - "lineage or active capital fence changed during execution" - ) - return binding - - -__all__ = [ - "ALPHA_PASSPORT_SCHEMA", - "CONTRACT_RESOLUTION_CHECKPOINT_SCHEMA", - "CONTRACT_RESOLUTION_SCHEMA", - "ContractResolutionResponse", - "ContractResolutionTransport", - "CoreAuthorityContractResolver", - "LineageResolutionError", - "PROMOTION_CERTIFICATE_SCHEMA", - "VerifiedLineageBinding", -] diff --git a/live_firewall/dumbmoney_reconciliation.py b/live_firewall/dumbmoney_reconciliation.py deleted file mode 100644 index 3527cd81..00000000 --- a/live_firewall/dumbmoney_reconciliation.py +++ /dev/null @@ -1,128 +0,0 @@ -"""Restart-safe read-only reconciliation orchestration for DumbMoney Dummy.""" - -from __future__ import annotations - -from collections.abc import Mapping -from typing import Any, Protocol - -from live_firewall.dumbmoney_capital import CapitalEnvelopeAdapter -from live_firewall.exposure_tracker import ExposureTracker - - -class SignedReconciliationReader(Protocol): - def terminal_reconciliation_witness( - self, - reservation: Mapping[str, Any], - ) -> Mapping[str, Any] | None: ... - - def settlement_reconciliation_witness( - self, - position_exposure: Mapping[str, Any], - ) -> Mapping[str, Any] | None: ... - - -class DumbMoneyKalshiReconciliationSweeper: - """Resolve prior dispatches before allowing another execution cycle.""" - - def __init__( - self, - *, - capital_adapter: CapitalEnvelopeAdapter, - broker_reader: SignedReconciliationReader, - exposure_tracker: ExposureTracker, - ) -> None: - self._capital_adapter = capital_adapter - self._broker_reader = broker_reader - self._exposure_tracker = exposure_tracker - - def run_once(self) -> dict[str, Any]: - broker_contacted = False - terminal_witnesses = 0 - settlement_witnesses = 0 - unresolved_reservations = 0 - unresolved_positions = 0 - - reservations = ( - self._capital_adapter.pending_reconciliation_reservations() - ) - for reservation in reservations: - if reservation.get("dispatch_claimed") is not True: - unresolved_reservations += 1 - continue - broker_contacted = True - wrapper = self._broker_reader.terminal_reconciliation_witness( - reservation - ) - if wrapper is None: - unresolved_reservations += 1 - continue - witness = ( - self._capital_adapter - .verify_terminal_reconciliation_witness(wrapper) - ) - terminal_state = ( - "filled" - if witness["terminal_status"] == "executed" - else "canceled" - ) - if not self._exposure_tracker.record_cumulative_fill( - str(witness["proposal_id"]), - int(witness["fill_count"]), - witness["average_fill_price_cents"], - terminal_state=terminal_state, - reconciliation_id=str(witness["witness_id"]), - ): - raise RuntimeError( - "local terminal exposure projection failed closed" - ) - self._capital_adapter.record_signed_terminal_reconciliation( - wrapper - ) - terminal_witnesses += 1 - - positions = self._capital_adapter.active_position_exposures() - for position in positions: - broker_contacted = True - wrapper = self._broker_reader.settlement_reconciliation_witness( - position - ) - if wrapper is None: - unresolved_positions += 1 - continue - witness = ( - self._capital_adapter - .verify_settlement_reconciliation_witness(wrapper) - ) - if not self._exposure_tracker.record_position_close( - str(witness["contract_ticker"]), - str(witness["side"]), - reconciliation_id=str(witness["witness_id"]), - ): - raise RuntimeError( - "local settlement projection failed closed" - ) - self._capital_adapter.record_signed_settlement_reconciliation( - wrapper - ) - settlement_witnesses += 1 - - blocked = bool( - unresolved_reservations or unresolved_positions - ) - return { - "schema": "dummy.kalshi-reconciliation-sweep.v1", - "status": "BLOCKED" if blocked else "COMPLETE", - "broker_contacted": broker_contacted, - "reservations_scanned": len(reservations), - "terminal_witnesses_recorded": terminal_witnesses, - "positions_scanned": len(positions), - "settlement_witnesses_recorded": settlement_witnesses, - "unresolved_reservations": unresolved_reservations, - "unresolved_positions": unresolved_positions, - } - - -__all__ = [ - "DumbMoneyKalshiReconciliationSweeper", - "SignedReconciliationReader", -] diff --git a/live_firewall/dumbmoney_windows_service.py b/live_firewall/dumbmoney_windows_service.py deleted file mode 100644 index bff5354e..00000000 --- a/live_firewall/dumbmoney_windows_service.py +++ /dev/null @@ -1,1857 +0,0 @@ -"""Sealed private-local Windows runner for the Dummy/Kalshi venue cell. - -Importing this module performs no I/O, starts no threads, and makes no network -request. The production entry point accepts only release-manifest arguments, -loads one raw-byte SHA-256-pinned public config from ProgramData, reads secrets -only from Windows Credential Manager, and always publishes -``RECONCILIATION_ONLY`` readiness before the first network operation. -""" -from __future__ import annotations - -import argparse -import base64 -import ctypes -import hashlib -import json -import os -import re -import signal -import sys -import threading -import uuid -from collections.abc import Callable, Mapping -from dataclasses import dataclass -from datetime import datetime, timedelta, timezone -from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer -from pathlib import Path -from typing import Any, Protocol -from urllib.parse import urlsplit - -import httpx -from cryptography.hazmat.primitives import serialization -from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey -from cryptography.hazmat.primitives.asymmetric.ed25519 import ( - Ed25519PrivateKey, -) - -from live_firewall.dumbmoney_capital import CapitalEnvelopeAdapter -from live_firewall.dumbmoney_command_feed import ( - CommandFeedResponse, - CoreCommandFeedConsumer, -) -from live_firewall.dumbmoney_execution_cycle import ( - SealedDisabledExecutionCycle, -) -from live_firewall.dumbmoney_lineage import ( - ContractResolutionResponse, - CoreAuthorityContractResolver, -) -from live_firewall.dumbmoney_journal_anchor import ( - CoreJournalAnchorClient, - JournalAnchorResponse, -) -from live_firewall.dumbmoney_reconciliation import ( - DumbMoneyKalshiReconciliationSweeper, -) -from live_firewall.exposure_tracker import ( - EXPOSURE_STATE_ANCHOR_SCHEMA, - ExposureTracker, -) -from live_firewall.kalshi_broker_truth import ( - KalshiBrokerTruthError, - KalshiBrokerTruthProvider, -) -from live_firewall.kalshi_reconciliation import ( - KalshiReconciliationReader, -) -from live_firewall.operational_journal import ( - canonical_json, - sha256_json, -) -from live_firewall.sqlite_operational_journal import SQLiteOperationalJournal - - -SERVICE_NAME = "DumbMoneyDummyKalshi" -CONFIG_SCHEMA = "dummy.dumbmoney-kalshi-runner-config.v1" -READINESS_SCHEMA = "dumbmoney.readiness-descriptor.v1" -HEALTH_SCHEMA = "dumbmoney.health.v1" -SIGNED_ENVELOPE_SCHEMA = "dumbmoney.signed-envelope.v1" -START_MODE = "RECONCILIATION_ONLY" -CORE_ENDPOINT_REF = "endpoint-ref:DumbMoneyCore" -CELL_TOKEN_TARGET_REF = "credential-target:DumbMoney/DummyCellToken" -KALSHI_KEY_ID_TARGET_REF = "credential-target:DumbMoney/KalshiApiKeyId" -KALSHI_PRIVATE_KEY_TARGET_REF = ( - "credential-target:DumbMoney/KalshiPrivateKeyPem" -) -READINESS_KEY_TARGET_REF = ( - "credential-target:DumbMoney/DummyReadinessEd25519" -) -READINESS_REF = "readiness-ref:DumbMoneyDummyKalshi" -CONFIG_RELATIVE_PATH = ( - Path("DumbMoney") / "config" / "dummy-kalshi-runner.v1.json" -) -CORE_READINESS_RELATIVE_PATH = ( - Path("DumbMoney") / "readiness" / "DumbMoneyCore.json" -) -READINESS_RELATIVE_PATH = ( - Path("DumbMoney") / "readiness" / f"{SERVICE_NAME}.json" -) -DATA_ROOT_RELATIVE_PATH = Path("DumbMoney") / "dummy-kalshi" -MAXIMUM_CONFIG_BYTES = 262_144 -MAXIMUM_READINESS_BYTES = 262_144 -_SHA256_RE = re.compile(r"^[0-9a-f]{64}$") -_TARGET_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._/-]{0,127}$") -_KEY_ID_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._:-]{7,255}$") -_CONFIG_FIELDS = { - "schema", - "service_name", - "release_id", - "core_endpoint_ref", - "core_readiness_path", - "core_cell_token_target", - "kalshi_key_id_target", - "kalshi_private_key_target", - "readiness_signing_key_target", - "start_mode", - "data_root", - "readiness_ref", - "readiness_path", - "core_public_keys_base64url", - "operator_public_keys_base64url", - "promoter_public_keys_base64url", - "research_public_keys_base64url", - "evaluator_public_keys_base64url", - "expected_account_hash", - "kalshi_subaccount_number", - "fund_lock_sha256", - "service_manifest_sha256", - "role_public_keys_sha256", - "core_runner_config_sha256", - "risk_policy_sha256", - "readiness_signer_public_key_sha256", - "poll_interval_seconds", - "readiness_ttl_seconds", - "broker_truth_max_age_seconds", -} -_CORE_READINESS_FIELDS = { - "schema", - "service_name", - "release_id", - "instance_id", - "process_id", - "generation", - "observed_at", - "valid_until", - "endpoint", - "fund_lock_sha256", - "service_manifest_sha256", - "authority", - "health", - "capabilities", -} - - -class DumbMoneyWindowsServiceError(RuntimeError): - """A sealed runner invariant failed closed.""" - - -class CredentialProvider(Protocol): - def read_bytes(self, target: str) -> bytes: ... - - -class BrokerTruthProvider(Protocol): - def snapshot(self) -> Mapping[str, Any]: ... - - -class ExecutionCycle(Protocol): - def __call__( - self, - *, - capital_adapter: CapitalEnvelopeAdapter, - command_feed: CoreCommandFeedConsumer, - broker_snapshot: Mapping[str, Any], - ) -> Mapping[str, Any]: ... - - -class WindowsCredentialManager: - """Read one Windows generic credential without logging its value.""" - - CRED_TYPE_GENERIC = 1 - - def read_bytes(self, target: str) -> bytes: - if not isinstance(target, str) or not _TARGET_RE.fullmatch(target): - raise DumbMoneyWindowsServiceError( - "Windows credential target is invalid" - ) - if os.name != "nt": - raise DumbMoneyWindowsServiceError( - "Windows Credential Manager is required" - ) - from ctypes import wintypes - - class FileTime(ctypes.Structure): - _fields_ = [ - ("low_datetime", wintypes.DWORD), - ("high_datetime", wintypes.DWORD), - ] - - class CredentialAttribute(ctypes.Structure): - _fields_ = [ - ("keyword", wintypes.LPWSTR), - ("flags", wintypes.DWORD), - ("value_size", wintypes.DWORD), - ("value", ctypes.POINTER(ctypes.c_ubyte)), - ] - - class Credential(ctypes.Structure): - _fields_ = [ - ("flags", wintypes.DWORD), - ("credential_type", wintypes.DWORD), - ("target_name", wintypes.LPWSTR), - ("comment", wintypes.LPWSTR), - ("last_written", FileTime), - ("credential_blob_size", wintypes.DWORD), - ("credential_blob", ctypes.POINTER(ctypes.c_ubyte)), - ("persist", wintypes.DWORD), - ("attribute_count", wintypes.DWORD), - ("attributes", ctypes.POINTER(CredentialAttribute)), - ("target_alias", wintypes.LPWSTR), - ("user_name", wintypes.LPWSTR), - ] - - pointer = ctypes.POINTER(Credential)() - advapi32 = ctypes.WinDLL("Advapi32.dll", use_last_error=True) - cred_read = advapi32.CredReadW - cred_read.argtypes = [ - wintypes.LPCWSTR, - wintypes.DWORD, - wintypes.DWORD, - ctypes.POINTER(ctypes.POINTER(Credential)), - ] - cred_read.restype = wintypes.BOOL - cred_free = advapi32.CredFree - cred_free.argtypes = [ctypes.c_void_p] - cred_free.restype = None - if not cred_read( - target, - self.CRED_TYPE_GENERIC, - 0, - ctypes.byref(pointer), - ): - code = ctypes.get_last_error() - raise DumbMoneyWindowsServiceError( - f"required Windows credential is unavailable; winerror={code}" - ) - try: - credential = pointer.contents - size = int(credential.credential_blob_size) - if not 1 <= size <= 65_536: - raise DumbMoneyWindowsServiceError( - "Windows credential blob size is invalid" - ) - return ctypes.string_at(credential.credential_blob, size) - finally: - cred_free(pointer) - - -@dataclass(frozen=True) -class DummyKalshiRunnerConfig: - release_id: str - core_readiness_path: Path - data_root: Path - readiness_path: Path - core_public_keys: Mapping[str, bytes] - operator_public_keys: Mapping[str, bytes] - promoter_public_keys: Mapping[str, bytes] - research_public_keys: Mapping[str, bytes] - evaluator_public_keys: Mapping[str, bytes] - expected_account_hash: str - kalshi_subaccount_number: int - fund_lock_sha256: str - service_manifest_sha256: str - role_public_keys_sha256: str - core_runner_config_sha256: str - risk_policy_sha256: str - readiness_signer_public_key_sha256: str - poll_interval_seconds: int - readiness_ttl_seconds: int - broker_truth_max_age_seconds: int - config_sha256: str - - -@dataclass(frozen=True) -class RunnerSecrets: - cell_token: str - kalshi_key_id: str - kalshi_private_key_pem: bytes - readiness_private_key: Ed25519PrivateKey - - -@dataclass(frozen=True) -class CoreEndpoint: - base_url: str - instance_id: str - observed_at: str - valid_until: str - - -@dataclass -class RunnerState: - mode: str = START_MODE - health_status: str = "BLOCKED" - reason: str = "RECONCILIATION_REQUIRED" - core_ready: bool = False - broker_truth_fresh: bool = False - rollback_anchor_current: bool = False - reconciled_once: bool = False - execution_enabled: bool = False - unresolved_open_orders: int = 0 - unresolved_positions: int = 0 - last_cycle_status: str = "not_started" - - -def _strict_json(raw: bytes, *, label: str) -> dict[str, Any]: - def reject_duplicates(pairs: list[tuple[str, Any]]) -> dict[str, Any]: - result: dict[str, Any] = {} - for key, value in pairs: - if key in result: - raise DumbMoneyWindowsServiceError( - f"{label} contains a duplicate JSON key" - ) - result[key] = value - return result - - try: - value = json.loads( - raw.decode("utf-8"), - object_pairs_hook=reject_duplicates, - parse_constant=lambda token: (_ for _ in ()).throw( - DumbMoneyWindowsServiceError( - f"{label} contains non-finite value {token}" - ) - ), - ) - except (UnicodeDecodeError, json.JSONDecodeError) as exc: - raise DumbMoneyWindowsServiceError( - f"{label} is not valid UTF-8 JSON" - ) from exc - if not isinstance(value, dict): - raise DumbMoneyWindowsServiceError(f"{label} must be a JSON object") - return value - - -def _digest(value: Any, *, field: str) -> str: - if not isinstance(value, str) or not _SHA256_RE.fullmatch(value): - raise DumbMoneyWindowsServiceError( - f"{field} must be a lowercase sha256" - ) - return value - - -def _public_key_map( - value: Any, - *, - role: str, - maximum_keys: int = 16, -) -> dict[str, bytes]: - if not isinstance(value, dict) or not 1 <= len(value) <= maximum_keys: - raise DumbMoneyWindowsServiceError( - f"{role} public-key map must contain 1 to {maximum_keys} keys" - ) - result: dict[str, bytes] = {} - for raw_key_id, raw_encoded in value.items(): - key_id = _digest(raw_key_id, field=f"{role} key id") - if ( - not isinstance(raw_encoded, str) - or "=" in raw_encoded - or re.search(r"[^A-Za-z0-9_-]", raw_encoded) - ): - raise DumbMoneyWindowsServiceError( - f"{role} public key encoding is invalid" - ) - try: - key = base64.urlsafe_b64decode( - raw_encoded + "=" * (-len(raw_encoded) % 4) - ) - except Exception as exc: - raise DumbMoneyWindowsServiceError( - f"{role} public key encoding is invalid" - ) from exc - if ( - len(key) != 32 - or hashlib.sha256(key).hexdigest() != key_id - ): - raise DumbMoneyWindowsServiceError( - f"{role} key id does not bind its Ed25519 key" - ) - result[key_id] = key - return result - - -def _fixed_path(value: Any, *, expected: Path, field: str) -> Path: - if not isinstance(value, str) or not value: - raise DumbMoneyWindowsServiceError(f"{field} must be an absolute path") - path = Path(value) - if not path.is_absolute() or path.resolve() != expected.resolve(): - raise DumbMoneyWindowsServiceError( - f"{field} differs from the fixed ProgramData path" - ) - return path.resolve() - - -def load_runner_config( - path: Path, - expected_sha256: str, - program_data: Path, -) -> DummyKalshiRunnerConfig: - """Load the fixed public config only after exact raw-byte pinning.""" - expected_digest = _digest(expected_sha256, field="config_sha256") - fixed = (program_data / CONFIG_RELATIVE_PATH).resolve() - if path.resolve() != fixed: - raise DumbMoneyWindowsServiceError( - "runner config path is not the fixed ProgramData path" - ) - try: - raw = path.read_bytes() - except OSError as exc: - raise DumbMoneyWindowsServiceError( - "pinned public runner config is unavailable" - ) from exc - if not 1 <= len(raw) <= MAXIMUM_CONFIG_BYTES: - raise DumbMoneyWindowsServiceError("runner config size is invalid") - if hashlib.sha256(raw).hexdigest() != expected_digest: - raise DumbMoneyWindowsServiceError( - "runner config does not match --config-sha256" - ) - payload = _strict_json(raw, label="runner config") - if set(payload) != _CONFIG_FIELDS: - raise DumbMoneyWindowsServiceError("runner config fields mismatch") - fixed_values = { - "schema": CONFIG_SCHEMA, - "service_name": SERVICE_NAME, - "core_endpoint_ref": CORE_ENDPOINT_REF, - "core_cell_token_target": CELL_TOKEN_TARGET_REF, - "kalshi_key_id_target": KALSHI_KEY_ID_TARGET_REF, - "kalshi_private_key_target": KALSHI_PRIVATE_KEY_TARGET_REF, - "readiness_signing_key_target": READINESS_KEY_TARGET_REF, - "start_mode": START_MODE, - "readiness_ref": READINESS_REF, - } - for field, expected in fixed_values.items(): - if payload[field] != expected: - raise DumbMoneyWindowsServiceError( - f"runner config {field} is not sealed" - ) - release_id = payload["release_id"] - if ( - not isinstance(release_id, str) - or release_id != release_id.strip() - or not release_id - ): - raise DumbMoneyWindowsServiceError("release_id is invalid") - core = _public_key_map( - payload["core_public_keys_base64url"], - role="Core", - ) - operator = _public_key_map( - payload["operator_public_keys_base64url"], - role="operator", - ) - promoter = _public_key_map( - payload["promoter_public_keys_base64url"], - role="promoter", - ) - research = _public_key_map( - payload["research_public_keys_base64url"], - role="research", - ) - evaluator = _public_key_map( - payload["evaluator_public_keys_base64url"], - role="evaluator", - maximum_keys=32, - ) - role_sets = [ - set(core), - set(operator), - set(promoter), - set(research), - set(evaluator), - ] - if len(set().union(*role_sets)) != sum(len(item) for item in role_sets): - raise DumbMoneyWindowsServiceError( - "Core/operator/promoter/research/evaluator signing roles overlap" - ) - subaccount = payload["kalshi_subaccount_number"] - if ( - isinstance(subaccount, bool) - or not isinstance(subaccount, int) - or subaccount != 0 - ): - raise DumbMoneyWindowsServiceError( - "kalshi_subaccount_number must be 0 until end-to-end " - "subaccount routing is sealed" - ) - poll_interval = payload["poll_interval_seconds"] - ttl = payload["readiness_ttl_seconds"] - truth_age = payload["broker_truth_max_age_seconds"] - if ( - isinstance(poll_interval, bool) - or not isinstance(poll_interval, int) - or not 5 <= poll_interval <= 300 - ): - raise DumbMoneyWindowsServiceError( - "poll_interval_seconds must be from 5 through 300" - ) - if ( - isinstance(ttl, bool) - or not isinstance(ttl, int) - or not 10 <= ttl <= 120 - ): - raise DumbMoneyWindowsServiceError( - "readiness_ttl_seconds must be from 10 through 120" - ) - if ( - isinstance(truth_age, bool) - or not isinstance(truth_age, int) - or not 5 <= truth_age <= 120 - ): - raise DumbMoneyWindowsServiceError( - "broker_truth_max_age_seconds must be from 5 through 120" - ) - return DummyKalshiRunnerConfig( - release_id=release_id, - core_readiness_path=_fixed_path( - payload["core_readiness_path"], - expected=program_data / CORE_READINESS_RELATIVE_PATH, - field="core_readiness_path", - ), - data_root=_fixed_path( - payload["data_root"], - expected=program_data / DATA_ROOT_RELATIVE_PATH, - field="data_root", - ), - readiness_path=_fixed_path( - payload["readiness_path"], - expected=program_data / READINESS_RELATIVE_PATH, - field="readiness_path", - ), - core_public_keys=core, - operator_public_keys=operator, - promoter_public_keys=promoter, - research_public_keys=research, - evaluator_public_keys=evaluator, - expected_account_hash=_digest( - payload["expected_account_hash"], - field="expected_account_hash", - ), - kalshi_subaccount_number=subaccount, - fund_lock_sha256=_digest( - payload["fund_lock_sha256"], - field="fund_lock_sha256", - ), - service_manifest_sha256=_digest( - payload["service_manifest_sha256"], - field="service_manifest_sha256", - ), - role_public_keys_sha256=_digest( - payload["role_public_keys_sha256"], - field="role_public_keys_sha256", - ), - core_runner_config_sha256=_digest( - payload["core_runner_config_sha256"], - field="core_runner_config_sha256", - ), - risk_policy_sha256=_digest( - payload["risk_policy_sha256"], - field="risk_policy_sha256", - ), - readiness_signer_public_key_sha256=_digest( - payload["readiness_signer_public_key_sha256"], - field="readiness_signer_public_key_sha256", - ), - poll_interval_seconds=poll_interval, - readiness_ttl_seconds=ttl, - broker_truth_max_age_seconds=truth_age, - config_sha256=expected_digest, - ) - - -def kalshi_account_hash(key_id: str, subaccount_number: int) -> str: - """Bind public config to the exact Credential Manager key and subaccount.""" - if not isinstance(key_id, str) or not _KEY_ID_RE.fullmatch(key_id): - raise DumbMoneyWindowsServiceError("Kalshi API key id is invalid") - if ( - isinstance(subaccount_number, bool) - or not isinstance(subaccount_number, int) - or subaccount_number != 0 - ): - raise DumbMoneyWindowsServiceError( - "Kalshi subaccount must be 0 until end-to-end routing is sealed" - ) - return hashlib.sha256( - canonical_json( - { - "schema": "dummy.kalshi-account-binding.v1", - "venue": "dummy_kalshi", - "api_key_id": key_id, - "subaccount_number": subaccount_number, - } - ).encode("utf-8") - ).hexdigest() - - -def _credential_target(reference: str, expected: str) -> str: - if reference != expected or not reference.startswith("credential-target:"): - raise DumbMoneyWindowsServiceError( - "credential reference is not the sealed target" - ) - return reference.removeprefix("credential-target:") - - -def _secret_text(raw: bytes, *, label: str, minimum: int = 16) -> str: - try: - value = raw.decode("utf-8") - except UnicodeDecodeError as exc: - raise DumbMoneyWindowsServiceError( - f"{label} credential is not UTF-8" - ) from exc - if ( - not minimum <= len(value) <= 65_536 - or value != value.strip() - or "\0" in value - ): - raise DumbMoneyWindowsServiceError( - f"{label} credential shape is invalid" - ) - return value - - -def _readiness_private_key(raw: bytes) -> Ed25519PrivateKey: - if len(raw) == 32: - return Ed25519PrivateKey.from_private_bytes(raw) - try: - key = serialization.load_pem_private_key(raw, password=None) - except (TypeError, ValueError) as exc: - raise DumbMoneyWindowsServiceError( - "readiness signing credential is not a private key" - ) from exc - if not isinstance(key, Ed25519PrivateKey): - raise DumbMoneyWindowsServiceError( - "readiness signing credential must be Ed25519" - ) - return key - - -def load_secrets( - provider: CredentialProvider, - config: DummyKalshiRunnerConfig, -) -> RunnerSecrets: - """Load exactly four sealed targets; there is no env or file fallback.""" - cell_token = _secret_text( - provider.read_bytes( - _credential_target( - CELL_TOKEN_TARGET_REF, - CELL_TOKEN_TARGET_REF, - ) - ), - label="cell bearer", - minimum=32, - ) - key_id = _secret_text( - provider.read_bytes( - _credential_target( - KALSHI_KEY_ID_TARGET_REF, - KALSHI_KEY_ID_TARGET_REF, - ) - ), - label="Kalshi key id", - minimum=8, - ) - if not _KEY_ID_RE.fullmatch(key_id): - raise DumbMoneyWindowsServiceError("Kalshi key id is invalid") - private_pem = provider.read_bytes( - _credential_target( - KALSHI_PRIVATE_KEY_TARGET_REF, - KALSHI_PRIVATE_KEY_TARGET_REF, - ) - ) - if not 128 <= len(private_pem) <= 65_536: - raise DumbMoneyWindowsServiceError( - "Kalshi private-key credential size is invalid" - ) - try: - kalshi_private_key = serialization.load_pem_private_key( - private_pem, - password=None, - ) - except (TypeError, ValueError) as exc: - raise DumbMoneyWindowsServiceError( - "Kalshi private-key credential is invalid" - ) from exc - if ( - not isinstance(kalshi_private_key, RSAPrivateKey) - or kalshi_private_key.key_size < 2_048 - ): - raise DumbMoneyWindowsServiceError( - "Kalshi private-key credential must be RSA with at least 2048 bits" - ) - readiness = _readiness_private_key( - provider.read_bytes( - _credential_target( - READINESS_KEY_TARGET_REF, - READINESS_KEY_TARGET_REF, - ) - ) - ) - readiness_public = readiness.public_key().public_bytes_raw() - if ( - hashlib.sha256(readiness_public).hexdigest() - != config.readiness_signer_public_key_sha256 - ): - raise DumbMoneyWindowsServiceError( - "readiness signing credential does not match public config" - ) - if ( - kalshi_account_hash(key_id, config.kalshi_subaccount_number) - != config.expected_account_hash - ): - raise DumbMoneyWindowsServiceError( - "Kalshi Credential Manager key/subaccount differs from account pin" - ) - return RunnerSecrets( - cell_token=cell_token, - kalshi_key_id=key_id, - kalshi_private_key_pem=bytes(private_pem), - readiness_private_key=readiness, - ) - - -def _parse_utc(value: Any, *, field: str) -> datetime: - if not isinstance(value, str) or not value.endswith("Z"): - raise DumbMoneyWindowsServiceError(f"{field} must be RFC3339 UTC") - try: - parsed = datetime.fromisoformat(value[:-1] + "+00:00") - except ValueError as exc: - raise DumbMoneyWindowsServiceError( - f"{field} must be RFC3339 UTC" - ) from exc - return parsed.astimezone(timezone.utc) - - -def _format_utc(value: datetime) -> str: - return value.astimezone(timezone.utc).isoformat().replace("+00:00", "Z") - - -def _core_endpoint_from_readiness( - config: DummyKalshiRunnerConfig, - *, - now: datetime, -) -> CoreEndpoint: - try: - raw = config.core_readiness_path.read_bytes() - except OSError as exc: - raise DumbMoneyWindowsServiceError( - "signed Core readiness is unavailable" - ) from exc - if not 1 <= len(raw) <= MAXIMUM_READINESS_BYTES: - raise DumbMoneyWindowsServiceError( - "signed Core readiness size is invalid" - ) - envelope = _strict_json(raw, label="signed Core readiness") - from live_firewall.dumbmoney_capital import verify_signed_envelope - - try: - signed = verify_signed_envelope( - envelope, - trusted_public_keys=config.core_public_keys, - now=now, - expected_body_schema=READINESS_SCHEMA, - max_ttl=timedelta(seconds=120), - ) - except ValueError as exc: - raise DumbMoneyWindowsServiceError( - f"signed Core readiness is invalid: {exc}" - ) from exc - body = signed.body - if set(body) != _CORE_READINESS_FIELDS: - raise DumbMoneyWindowsServiceError( - "Core readiness descriptor fields mismatch" - ) - if ( - body["schema"] != READINESS_SCHEMA - or body["service_name"] != "DumbMoneyCore" - or body["release_id"] != config.release_id - ): - raise DumbMoneyWindowsServiceError( - "Core readiness identity or release mismatch" - ) - observed = _parse_utc(body["observed_at"], field="Core observed_at") - valid = _parse_utc(body["valid_until"], field="Core valid_until") - if ( - not observed <= now < valid - or signed.not_before != observed - or signed.expires_at != valid - ): - raise DumbMoneyWindowsServiceError( - "Core readiness window is invalid" - ) - if ( - body["fund_lock_sha256"] != config.fund_lock_sha256 - or body["service_manifest_sha256"] - != config.service_manifest_sha256 - ): - raise DumbMoneyWindowsServiceError("Core readiness release pin mismatch") - authority = body["authority"] - if authority != { - "broker": "NONE", - "mode": "OFFLINE", - "execution_enabled": False, - }: - raise DumbMoneyWindowsServiceError( - "Core readiness claims broker authority" - ) - health = body["health"] - if not isinstance(health, dict): - raise DumbMoneyWindowsServiceError("Core health is invalid") - expected_health = { - "role_public_keys_sha256": config.role_public_keys_sha256, - "runner_config_sha256": config.core_runner_config_sha256, - "risk_policy_sha256": config.risk_policy_sha256, - } - for field, expected in expected_health.items(): - if health.get(field) != expected: - raise DumbMoneyWindowsServiceError( - f"Core health pin mismatch: {field}" - ) - if health.get("status") not in {"READY", "DEGRADED"}: - raise DumbMoneyWindowsServiceError("Core readiness is blocked") - endpoint = body["endpoint"] - if not isinstance(endpoint, dict) or set(endpoint) != { - "transport", - "host", - "port", - "base_path", - }: - raise DumbMoneyWindowsServiceError("Core endpoint is invalid") - host = endpoint["host"] - port = endpoint["port"] - if ( - endpoint["transport"] != "http" - or host not in {"127.0.0.1", "::1"} - or endpoint["base_path"] != "/" - or isinstance(port, bool) - or not isinstance(port, int) - or not 1024 <= port <= 65_535 - ): - raise DumbMoneyWindowsServiceError( - "Core endpoint is not literal loopback HTTP" - ) - instance_id = body["instance_id"] - try: - if str(uuid.UUID(instance_id)) != instance_id: - raise ValueError - except (AttributeError, ValueError) as exc: - raise DumbMoneyWindowsServiceError( - "Core instance id is invalid" - ) from exc - base = f"http://[{host}]:{port}" if host == "::1" else f"http://{host}:{port}" - return CoreEndpoint( - base_url=base, - instance_id=instance_id, - observed_at=body["observed_at"], - valid_until=body["valid_until"], - ) - - -class LoopbackCoreTransport: - """No-proxy, no-redirect transport pinned to a validated Core endpoint.""" - - def __init__(self) -> None: - self._endpoint: CoreEndpoint | None = None - self._client = httpx.Client( - timeout=5.0, - follow_redirects=False, - trust_env=False, - ) - - def set_endpoint(self, endpoint: CoreEndpoint) -> None: - parsed = urlsplit(endpoint.base_url) - if ( - parsed.scheme != "http" - or parsed.hostname not in {"127.0.0.1", "::1"} - or parsed.username is not None - or parsed.password is not None - ): - raise DumbMoneyWindowsServiceError( - "Core transport endpoint is not literal loopback" - ) - self._endpoint = endpoint - - def _get( - self, - path: str, - headers: Mapping[str, str], - ) -> tuple[int, bytes]: - endpoint = self._endpoint - if endpoint is None: - raise DumbMoneyWindowsServiceError( - "Core endpoint has not been authenticated" - ) - if ( - not isinstance(path, str) - or not path.startswith("/") - or path.startswith("//") - or "\\" in path - ): - raise DumbMoneyWindowsServiceError("Core request path is invalid") - response = self._client.get( - f"{endpoint.base_url}{path}", - headers=dict(headers), - ) - return response.status_code, bytes(response.content) - - def command_get( - self, - path: str, - headers: Mapping[str, str], - ) -> CommandFeedResponse: - status, body = self._get(path, headers) - return CommandFeedResponse( - status_code=status, - body=body, - ) - - def contract_get( - self, - path: str, - headers: Mapping[str, str], - ) -> ContractResolutionResponse: - status, body = self._get(path, headers) - return ContractResolutionResponse( - status_code=status, - body=body, - ) - - def journal_anchor_post( - self, - path: str, - headers: Mapping[str, str], - body: bytes, - ) -> JournalAnchorResponse: - endpoint = self._endpoint - if endpoint is None: - raise DumbMoneyWindowsServiceError( - "Core endpoint has not been authenticated" - ) - if ( - path - != "/v1/cells/dummy_kalshi/journal-heads:anchor" - or not isinstance(body, bytes) - or not 1 <= len(body) <= 262_144 - ): - raise DumbMoneyWindowsServiceError( - "Core journal anchor request is invalid" - ) - response = self._client.post( - f"{endpoint.base_url}{path}", - headers=dict(headers), - content=body, - ) - return JournalAnchorResponse( - status_code=response.status_code, - body=bytes(response.content), - ) - - def liveness(self) -> None: - endpoint = self._endpoint - if endpoint is None: - raise DumbMoneyWindowsServiceError( - "Core endpoint has not been authenticated" - ) - response = self._client.get( - f"{endpoint.base_url}/health/live", - headers={"Accept": "application/json"}, - ) - if response.status_code != 200 or len(response.content) > 16_384: - raise DumbMoneyWindowsServiceError("Core liveness probe failed") - if _strict_json( - bytes(response.content), - label="Core liveness", - ) != {"schema": HEALTH_SCHEMA, "status": "LIVE"}: - raise DumbMoneyWindowsServiceError( - "Core liveness payload is invalid" - ) - - def close(self) -> None: - self._client.close() - - -def _atomic_write_json(path: Path, payload: Mapping[str, Any]) -> None: - path.parent.mkdir(parents=True, exist_ok=True) - temporary = path.with_name( - f".{path.name}.{os.getpid()}.{uuid.uuid4().hex}.tmp" - ) - encoded = canonical_json(dict(payload)).encode("utf-8") + b"\n" - try: - with temporary.open("xb") as handle: - handle.write(encoded) - handle.flush() - os.fsync(handle.fileno()) - os.replace(temporary, path) - finally: - temporary.unlink(missing_ok=True) - - -class _HealthServer: - def __init__(self, state_reader: Callable[[], RunnerState]) -> None: - read_state = state_reader - - class Handler(BaseHTTPRequestHandler): - def do_GET(self) -> None: # noqa: N802 - if self.path == "/health/live": - self._write( - 200, - {"schema": HEALTH_SCHEMA, "status": "LIVE"}, - ) - return - if self.path == "/health/ready": - state = read_state() - ready = ( - state.health_status == "READY" - and state.reconciled_once - ) - self._write( - 200 if ready else 503, - { - "schema": HEALTH_SCHEMA, - "status": "READY" if ready else "NOT_READY", - "reason_codes": [] if ready else [state.reason], - }, - ) - return - self._write( - 404, - {"schema": HEALTH_SCHEMA, "status": "NOT_FOUND"}, - ) - - def _write(self, status: int, payload: Mapping[str, Any]) -> None: - encoded = canonical_json(dict(payload)).encode("utf-8") - self.send_response(status) - self.send_header("Content-Type", "application/json") - self.send_header("Cache-Control", "no-store") - self.send_header("Content-Length", str(len(encoded))) - self.end_headers() - self.wfile.write(encoded) - - def log_message(self, _format: str, *_args: Any) -> None: - return - - self.server = ThreadingHTTPServer(("127.0.0.1", 0), Handler) - self.thread = threading.Thread( - target=self.server.serve_forever, - name=f"{SERVICE_NAME}-health", - daemon=True, - ) - - @property - def port(self) -> int: - return int(self.server.server_address[1]) - - def start(self) -> None: - self.thread.start() - - def close(self) -> None: - self.server.shutdown() - self.server.server_close() - self.thread.join(timeout=5.0) - - -class DumbMoneyDummyKalshiService: - """Continuous control/reconciliation supervisor; never a second order sink.""" - - def __init__( - self, - config: DummyKalshiRunnerConfig, - secrets: RunnerSecrets, - *, - core_transport: LoopbackCoreTransport, - broker_truth: BrokerTruthProvider, - execution_cycle: ExecutionCycle | None = None, - reconciliation_sweeper: ( - DumbMoneyKalshiReconciliationSweeper | None - ) = None, - journal_anchor_client: CoreJournalAnchorClient | None = None, - clock: Callable[[], datetime] = lambda: datetime.now(timezone.utc), - ) -> None: - self.config = config - self.secrets = secrets - self.core_transport = core_transport - self.broker_truth = broker_truth - self.execution_cycle = execution_cycle - self._reconciliation_sweeper = reconciliation_sweeper - self._journal_anchor_client = journal_anchor_client - self.clock = clock - self.instance_id = str(uuid.uuid4()) - self._state = RunnerState() - self._state_lock = threading.Lock() - self._readiness_sequence = 0 - self._health = _HealthServer(self.state) - self._components_ready = False - self._capital_adapter: CapitalEnvelopeAdapter | None = None - self._command_feed: CoreCommandFeedConsumer | None = None - self._capital_journal: SQLiteOperationalJournal | None = None - self._command_journal: SQLiteOperationalJournal | None = None - self._exposure_tracker: ExposureTracker | None = None - - def state(self) -> RunnerState: - with self._state_lock: - return RunnerState(**self._state.__dict__) - - def _set_state(self, **changes: Any) -> None: - with self._state_lock: - for field, value in changes.items(): - setattr(self._state, field, value) - - def _clock(self) -> datetime: - now = self.clock() - if now.tzinfo is None or now.utcoffset() is None: - raise DumbMoneyWindowsServiceError( - "runner clock must be timezone-aware" - ) - return now.astimezone(timezone.utc) - - def start(self) -> None: - """Publish blocked readiness without any Core or broker call.""" - self.config.data_root.mkdir(parents=True, exist_ok=True) - self.config.readiness_path.parent.mkdir(parents=True, exist_ok=True) - self._health.start() - self.write_readiness() - - def close(self) -> None: - try: - broker_close = getattr(self.broker_truth, "close", None) - if callable(broker_close): - broker_close() - finally: - try: - self._health.close() - finally: - try: - if self._command_journal is not None: - self._command_journal.close() - self._command_journal = None - finally: - try: - if self._capital_journal is not None: - self._capital_journal.close() - self._capital_journal = None - finally: - self.core_transport.close() - - def _initialize_components(self) -> None: - if self._components_ready: - return - capital_journal = SQLiteOperationalJournal( - self.config.data_root / "capital-operational.db", - now_fn=self._clock, - ) - if not capital_journal.healthy: - capital_journal.close() - raise DumbMoneyWindowsServiceError( - "capital operational journal is unhealthy" - ) - command_journal: SQLiteOperationalJournal | None = None - try: - resolver = CoreAuthorityContractResolver( - transport=self.core_transport.contract_get, - cell_token_provider=lambda: self.secrets.cell_token, - trusted_core_public_keys=self.config.core_public_keys, - trusted_research_public_keys=self.config.research_public_keys, - trusted_promoter_public_keys=self.config.promoter_public_keys, - trusted_evaluator_public_keys=self.config.evaluator_public_keys, - now_fn=self._clock, - ) - adapter = CapitalEnvelopeAdapter( - journal=capital_journal, - trusted_public_keys=self.config.core_public_keys, - expected_venue="dummy_kalshi", - expected_account_hash=self.config.expected_account_hash, - lineage_resolver=resolver, - trusted_broker_witness_public_keys={ - self.config.readiness_signer_public_key_sha256: ( - self.secrets.readiness_private_key.public_key() - ) - }, - now_fn=self._clock, - max_bootstrap_age=timedelta( - seconds=self.config.broker_truth_max_age_seconds - ), - ) - - def reduce_authority(_command: Any) -> None: - self._set_state( - mode=START_MODE, - health_status="BLOCKED", - reason="CORE_AUTHORITY_REDUCED", - execution_enabled=False, - ) - - def fail_closed(reason: str) -> None: - self._set_state( - mode=START_MODE, - health_status="BLOCKED", - reason=reason, - core_ready=False, - execution_enabled=False, - ) - - command_journal = SQLiteOperationalJournal( - self.config.data_root / "command-feed.db", - now_fn=self._clock, - ) - if not command_journal.healthy: - raise DumbMoneyWindowsServiceError( - "command-feed operational journal is unhealthy" - ) - command_feed = CoreCommandFeedConsumer( - transport=self.core_transport.command_get, - cell_token_provider=lambda: self.secrets.cell_token, - state_journal=command_journal, - trusted_operator_public_keys=self.config.operator_public_keys, - trusted_checkpoint_public_keys=self.config.core_public_keys, - capital_adapter=adapter, - kill_handler=reduce_authority, - mode_handler=reduce_authority, - fail_closed_handler=fail_closed, - now_fn=self._clock, - ) - exposure = ExposureTracker( - persist=True, - state_path=( - self.config.data_root - / "live-exposure-state.json" - ), - ) - if not exposure.state_healthy: - raise DumbMoneyWindowsServiceError( - "live exposure projection is unhealthy" - ) - if ( - self._reconciliation_sweeper is None - and isinstance( - self.broker_truth, - KalshiBrokerTruthProvider, - ) - ): - reader = KalshiReconciliationReader( - broker_truth=self.broker_truth, - witness_signing_private_key=( - self.secrets.readiness_private_key - ), - ) - self._reconciliation_sweeper = ( - DumbMoneyKalshiReconciliationSweeper( - capital_adapter=adapter, - broker_reader=reader, - exposure_tracker=exposure, - ) - ) - if self._journal_anchor_client is None: - self._journal_anchor_client = CoreJournalAnchorClient( - transport=self.core_transport.journal_anchor_post, - cell_token_provider=lambda: self.secrets.cell_token, - trusted_core_public_keys=self.config.core_public_keys, - expected_account_hash=( - self.config.expected_account_hash - ), - now_fn=self._clock, - ) - except BaseException: - if command_journal is not None: - command_journal.close() - capital_journal.close() - raise - self._capital_adapter = adapter - self._command_feed = command_feed - self._capital_journal = capital_journal - self._command_journal = command_journal - self._exposure_tracker = exposure - self._components_ready = True - - def _anchor_local_state(self) -> None: - client = self._journal_anchor_client - capital = self._capital_journal - command = self._command_journal - exposure = self._exposure_tracker - if ( - client is None - or capital is None - or command is None - or exposure is None - ): - raise DumbMoneyWindowsServiceError( - "rollback anchor components are unavailable" - ) - capital_sequence, capital_head = capital.head() - command_sequence, command_head = command.head() - exposure_sequence, exposure_head = exposure.anchor_head() - sources = ( - ( - "capital-operational", - "dummy.sqlite-operational-journal.v1", - capital_sequence, - capital_head, - ), - ( - "command-feed", - "dummy.sqlite-operational-journal.v1", - command_sequence, - command_head, - ), - ( - "live-exposure", - EXPOSURE_STATE_ANCHOR_SCHEMA, - exposure_sequence, - exposure_head, - ), - ) - for name, schema, sequence, head in sources: - client.anchor( - journal_name=name, - journal_schema=schema, - journal_sequence=sequence, - journal_head_sha256=head, - ) - - def _record_broker_truth(self, raw: Mapping[str, Any]) -> tuple[int, int]: - payload = json.loads(canonical_json(dict(raw))) - required = { - "schema", - "venue", - "account_hash", - "subaccount_number", - "observed_at", - "broker_snapshot_sha256", - "flat_book_observed", - "total_exposure_cents", - "open_order_count", - "market_exposure_cents", - "correlated_exposure_cents", - "unresolved_open_orders", - "unresolved_positions", - } - if set(payload) != required: - raise DumbMoneyWindowsServiceError( - "broker truth snapshot fields mismatch" - ) - if ( - payload["schema"] != "dummy.kalshi-broker-truth.v1" - or payload["venue"] != "dummy_kalshi" - or payload["account_hash"] != self.config.expected_account_hash - or payload["subaccount_number"] - != self.config.kalshi_subaccount_number - ): - raise DumbMoneyWindowsServiceError( - "broker truth identity mismatch" - ) - observed = _parse_utc( - payload["observed_at"], - field="broker truth observed_at", - ) - now = self._clock() - if ( - observed > now + timedelta(seconds=5) - or now - observed - > timedelta(seconds=self.config.broker_truth_max_age_seconds) - ): - raise DumbMoneyWindowsServiceError("broker truth is stale") - _digest( - payload["broker_snapshot_sha256"], - field="broker_snapshot_sha256", - ) - integers = ( - "total_exposure_cents", - "open_order_count", - "unresolved_open_orders", - "unresolved_positions", - ) - for field in integers: - value = payload[field] - if ( - isinstance(value, bool) - or not isinstance(value, int) - or value < 0 - ): - raise DumbMoneyWindowsServiceError( - f"broker truth {field} is invalid" - ) - unresolved_orders = payload["unresolved_open_orders"] - unresolved_positions = payload["unresolved_positions"] - flat = ( - payload["flat_book_observed"] is True - and payload["total_exposure_cents"] == 0 - and payload["open_order_count"] == 0 - and unresolved_orders == 0 - and unresolved_positions == 0 - and payload["market_exposure_cents"] == {} - and payload["correlated_exposure_cents"] == {} - ) - if payload["flat_book_observed"] is not flat: - raise DumbMoneyWindowsServiceError( - "broker flat-book projection is inconsistent" - ) - assert self._capital_adapter is not None - receipt = { - "schema": ( - "dummy.broker-bootstrap.flat.v1" - if flat - else "dummy.broker-bootstrap.inherited-exposure.v1" - ), - "receipt_id": sha256_json(payload), - "venue": payload["venue"], - "account_hash": payload["account_hash"], - "observed_at": payload["observed_at"], - "broker_snapshot_sha256": payload["broker_snapshot_sha256"], - "flat_book_observed": flat, - "total_exposure_cents": payload["total_exposure_cents"], - "open_order_count": payload["open_order_count"], - "market_exposure_cents": payload["market_exposure_cents"], - "correlated_exposure_cents": payload[ - "correlated_exposure_cents" - ], - } - self._capital_adapter.record_broker_bootstrap(receipt) - return unresolved_orders, unresolved_positions - - def run_once(self) -> Mapping[str, Any]: - """Poll controls and broker truth once; writes remain disabled on pass one.""" - now = self._clock() - prior = self.state() - try: - endpoint = _core_endpoint_from_readiness( - self.config, - now=now, - ) - self.core_transport.set_endpoint(endpoint) - self.core_transport.liveness() - self._initialize_components() - self._anchor_local_state() - assert self._command_feed is not None - poll = self._command_feed.poll_once() - core_ready = ( - poll.page_accepted - and poll.submission_allowed - and self._command_feed.submission_allowed() - ) - truth = self.broker_truth.snapshot() - unresolved_orders, unresolved_positions = ( - self._record_broker_truth(truth) - ) - if self._reconciliation_sweeper is not None: - sweep = self._reconciliation_sweeper.run_once() - unresolved_orders += int( - sweep["unresolved_reservations"] - ) - unresolved_positions += int( - sweep["unresolved_positions"] - ) - flat = unresolved_orders == 0 and unresolved_positions == 0 - reconciled = flat and core_ready - # Reconciliation-only is sticky for the first successful pass. - cycle = self.execution_cycle - may_execute = ( - prior.reconciled_once - and reconciled - and cycle is not None - ) - cycle_result: Mapping[str, Any] = { - "schema": "dummy.dumbmoney-execution-cycle.v1", - "status": "RECONCILIATION_COMPLETE" - if reconciled - else "RECONCILIATION_BLOCKED", - "broker_contacted": True, - "orders_submitted": 0, - "broker_snapshot_sha256": truth[ - "broker_snapshot_sha256" - ], - } - if may_execute: - assert self._capital_adapter is not None - assert cycle is not None - cycle_result = cycle( - capital_adapter=self._capital_adapter, - command_feed=self._command_feed, - broker_snapshot=truth, - ) - if set(cycle_result) != { - "schema", - "status", - "broker_contacted", - "orders_submitted", - "broker_snapshot_sha256", - }: - raise DumbMoneyWindowsServiceError( - "execution cycle result fields mismatch" - ) - if ( - cycle_result["schema"] - != "dummy.dumbmoney-execution-cycle.v1" - or cycle_result["status"] - not in {"COMPLETE", "BLOCKED"} - or not isinstance( - cycle_result["broker_contacted"], - bool, - ) - or isinstance(cycle_result["orders_submitted"], bool) - or not isinstance( - cycle_result["orders_submitted"], - int, - ) - or cycle_result["orders_submitted"] < 0 - or cycle_result["broker_snapshot_sha256"] - != truth["broker_snapshot_sha256"] - ): - raise DumbMoneyWindowsServiceError( - "execution cycle result is invalid" - ) - self._anchor_local_state() - execution_enabled = bool( - may_execute - and cycle_result.get("status") == "COMPLETE" - and unresolved_orders == 0 - and unresolved_positions == 0 - ) - cycle_blocked = ( - may_execute - and cycle_result.get("status") != "COMPLETE" - ) - reason = ( - "UNRESOLVED_BROKER_ORDERS_OR_POSITIONS" - if not flat - else ( - "CORE_CONTROLS_NOT_CURRENT" - if not core_ready - else ( - "EXECUTION_CYCLE_BLOCKED" - if cycle_blocked - else ( - "EXECUTION_CYCLE_NOT_SEALED" - if cycle is None - else ( - "INITIAL_RECONCILIATION_COMPLETE" - if not prior.reconciled_once - else "ALL_CURRENT_CONTROLS_ALLOW" - ) - ) - ) - ) - ) - self._set_state( - mode=( - "AGGRESSIVE_BOUNDED" - if execution_enabled - else START_MODE - ), - health_status=( - "READY" - if execution_enabled - else "BLOCKED" - ), - reason=reason, - core_ready=core_ready, - broker_truth_fresh=True, - rollback_anchor_current=True, - reconciled_once=reconciled, - execution_enabled=execution_enabled, - unresolved_open_orders=unresolved_orders, - unresolved_positions=unresolved_positions, - last_cycle_status=str( - cycle_result.get("status", "unknown") - ), - ) - self.write_readiness() - return cycle_result - except Exception as exc: - self._set_state( - mode=START_MODE, - health_status="BLOCKED", - reason=f"cycle_failed_closed:{type(exc).__name__}", - core_ready=False, - broker_truth_fresh=False, - rollback_anchor_current=False, - reconciled_once=False, - execution_enabled=False, - last_cycle_status="cycle_failed_closed", - ) - self.write_readiness() - raise - - def write_readiness(self) -> dict[str, Any]: - now = self._clock() - valid_until = now + timedelta( - seconds=self.config.readiness_ttl_seconds - ) - state = self.state() - self._readiness_sequence += 1 - body = { - "schema": READINESS_SCHEMA, - "service_name": SERVICE_NAME, - "release_id": self.config.release_id, - "instance_id": self.instance_id, - "process_id": os.getpid(), - "generation": self._readiness_sequence, - "observed_at": _format_utc(now), - "valid_until": _format_utc(valid_until), - "endpoint": { - "transport": "http", - "host": "127.0.0.1", - "port": self._health.port, - "base_path": "/", - }, - "fund_lock_sha256": self.config.fund_lock_sha256, - "service_manifest_sha256": ( - self.config.service_manifest_sha256 - ), - "authority": { - "broker": "KALSHI", - "mode": state.mode, - "execution_enabled": state.execution_enabled, - }, - "health": { - "status": state.health_status, - "reason_codes": [state.reason], - "core_ready": state.core_ready, - "broker_truth_fresh": state.broker_truth_fresh, - "rollback_anchor_current": ( - state.rollback_anchor_current - ), - "reconciled_once": state.reconciled_once, - "unresolved_open_orders": state.unresolved_open_orders, - "unresolved_positions": state.unresolved_positions, - "last_cycle_status": state.last_cycle_status, - "runner_config_sha256": self.config.config_sha256, - "readiness_public_key_sha256": ( - self.config.readiness_signer_public_key_sha256 - ), - }, - "capabilities": [ - "authenticated-promotion-resolution", - "broker-reconciliation", - "cell-command-checkpoints", - "canonical-live-firewall-only", - "core-journal-head-anchors", - ], - } - unsigned = { - "schema": SIGNED_ENVELOPE_SCHEMA, - "source_id": SERVICE_NAME, - "source_sequence": self._readiness_sequence, - "correlation_id": f"readiness-{self.instance_id}", - "causation_id": None, - "nonce": hashlib.sha256( - canonical_json( - { - "instance_id": self.instance_id, - "sequence": self._readiness_sequence, - "observed_at": body["observed_at"], - } - ).encode("utf-8") - ).hexdigest(), - "not_before": body["observed_at"], - "expires_at": body["valid_until"], - "body_schema": READINESS_SCHEMA, - "body_digest": sha256_json(body), - "body": body, - "signature_algorithm": "Ed25519", - "signer_key_id": ( - self.config.readiness_signer_public_key_sha256 - ), - } - unsigned["event_id"] = sha256_json(unsigned) - signature = self.secrets.readiness_private_key.sign( - canonical_json(unsigned).encode("utf-8") - ) - envelope = { - **unsigned, - "signature": base64.urlsafe_b64encode(signature) - .decode("ascii") - .rstrip("="), - } - _atomic_write_json(self.config.readiness_path, envelope) - return envelope - - def run_forever(self, stop_event: threading.Event) -> None: - self.start() - try: - while not stop_event.is_set(): - if stop_event.wait(self.config.poll_interval_seconds): - break - try: - self.run_once() - except Exception: - # run_once already persisted a short-lived signed blocked - # readiness descriptor. Continue polling for recovery. - continue - finally: - self.close() - - -class _DataRootLease: - def __init__(self, path: Path) -> None: - self.path = path - self.handle: Any = None - - def __enter__(self) -> "_DataRootLease": - self.path.parent.mkdir(parents=True, exist_ok=True) - self.handle = self.path.open("a+b") - try: - self.handle.seek(0) - import msvcrt - - msvcrt.locking(self.handle.fileno(), msvcrt.LK_NBLCK, 1) - except (ImportError, OSError) as exc: - self.handle.close() - raise DumbMoneyWindowsServiceError( - "another Dummy service owns the ProgramData root" - ) from exc - return self - - def __exit__(self, *_args: Any) -> None: - if self.handle is None or self.handle.closed: - return - try: - self.handle.seek(0) - import msvcrt - - msvcrt.locking(self.handle.fileno(), msvcrt.LK_UNLCK, 1) - finally: - self.handle.close() - - -def _program_data_path() -> Path: - value = os.environ.get("PROGRAMDATA", "") - if not value: - raise DumbMoneyWindowsServiceError( - "PROGRAMDATA is required for the sealed Windows service" - ) - path = Path(value).resolve() - if not path.is_absolute(): - raise DumbMoneyWindowsServiceError("PROGRAMDATA must be absolute") - return path - - -def _parser() -> argparse.ArgumentParser: - parser = argparse.ArgumentParser( - prog=SERVICE_NAME, - description="Sealed DumbMoney Dummy/Kalshi venue-cell service", - allow_abbrev=False, - ) - parser.add_argument("--core-endpoint-ref", required=True) - parser.add_argument("--core-cell-token-target", required=True) - parser.add_argument("--kalshi-key-id-target", required=True) - parser.add_argument("--kalshi-private-key-target", required=True) - parser.add_argument("--readiness-signing-key-target", required=True) - parser.add_argument("--start-mode", required=True) - parser.add_argument("--readiness-ref", required=True) - parser.add_argument("--config-sha256", required=True) - return parser - - -def _validate_cli(arguments: argparse.Namespace) -> None: - expected = { - "core_endpoint_ref": CORE_ENDPOINT_REF, - "core_cell_token_target": CELL_TOKEN_TARGET_REF, - "kalshi_key_id_target": KALSHI_KEY_ID_TARGET_REF, - "kalshi_private_key_target": KALSHI_PRIVATE_KEY_TARGET_REF, - "readiness_signing_key_target": READINESS_KEY_TARGET_REF, - "start_mode": START_MODE, - "readiness_ref": READINESS_REF, - } - for field, value in expected.items(): - if getattr(arguments, field) != value: - raise DumbMoneyWindowsServiceError( - f"sealed service argument mismatch: {field}" - ) - _digest(arguments.config_sha256, field="--config-sha256") - - -def main(argv: list[str] | None = None) -> int: - """Synchronous sealed-packaging entry point.""" - try: - arguments = _parser().parse_args(argv) - _validate_cli(arguments) - program_data = _program_data_path() - config = load_runner_config( - program_data / CONFIG_RELATIVE_PATH, - arguments.config_sha256, - program_data, - ) - secrets_value = load_secrets(WindowsCredentialManager(), config) - service = DumbMoneyDummyKalshiService( - config, - secrets_value, - core_transport=LoopbackCoreTransport(), - broker_truth=KalshiBrokerTruthProvider( - api_key_id=secrets_value.kalshi_key_id, - private_key_pem=secrets_value.kalshi_private_key_pem, - expected_account_hash=config.expected_account_hash, - subaccount_number=config.kalshi_subaccount_number, - ), - execution_cycle=SealedDisabledExecutionCycle(), - ) - stop_event = threading.Event() - - def stop(_signum: int, _frame: Any) -> None: - stop_event.set() - - for signal_name in ("SIGINT", "SIGTERM"): - candidate = getattr(signal, signal_name, None) - if candidate is not None: - signal.signal(candidate, stop) - with _DataRootLease(config.data_root / "service.lock"): - service.run_forever(stop_event) - return 0 - except KeyboardInterrupt: - return 0 - except ( - DumbMoneyWindowsServiceError, - KalshiBrokerTruthError, - OSError, - ValueError, - ) as exc: - print( - f"{SERVICE_NAME} failed closed: {type(exc).__name__}", - file=sys.stderr, - ) - return 2 - - -if __name__ == "__main__": - raise SystemExit(main()) - - -__all__ = [ - "CELL_TOKEN_TARGET_REF", - "CONFIG_RELATIVE_PATH", - "CONFIG_SCHEMA", - "CORE_ENDPOINT_REF", - "DATA_ROOT_RELATIVE_PATH", - "DumbMoneyDummyKalshiService", - "DumbMoneyWindowsServiceError", - "DummyKalshiRunnerConfig", - "KALSHI_KEY_ID_TARGET_REF", - "KALSHI_PRIVATE_KEY_TARGET_REF", - "KalshiBrokerTruthProvider", - "LoopbackCoreTransport", - "READINESS_KEY_TARGET_REF", - "READINESS_REF", - "RunnerSecrets", - "SealedDisabledExecutionCycle", - "SERVICE_NAME", - "START_MODE", - "WindowsCredentialManager", - "kalshi_account_hash", - "load_runner_config", - "load_secrets", - "main", -] diff --git a/live_firewall/exposure_tracker.py b/live_firewall/exposure_tracker.py index 3334be18..ccce925b 100644 --- a/live_firewall/exposure_tracker.py +++ b/live_firewall/exposure_tracker.py @@ -3,24 +3,14 @@ import json import math import os -from collections.abc import Callable from datetime import datetime, timezone, timedelta from pathlib import Path from typing import Any -from uuid import uuid4 -from core.interprocess_lock import InterprocessFileLock from core.ontology import Position -from autonomy.fees import kalshi_taker_fee_cents -from live_firewall.operational_journal import canonical_json, sha256_json DEFAULT_EXPOSURE_STATE_PATH = Path(__file__).resolve().parents[1] / "runtime" / "live_exposure_state.json" -EXPOSURE_STATE_ANCHOR_SCHEMA = "dummy.live-exposure-state.v1" -_FAIL_CLOSED_EXPOSURE_CENTS = 2**63 - 1 -_OPEN_ORDER_STATES = frozenset( - {"open", "submitting", "submit_outcome_unknown", "partially_filled"} -) class ExposureTracker: @@ -29,15 +19,9 @@ class ExposureTracker: def __init__(self, *, persist: bool = False, state_path: Path | None = None): configured_path = os.environ.get("DUMMY_EXPOSURE_STATE_PATH") self.state_path = state_path or (Path(configured_path) if configured_path else DEFAULT_EXPOSURE_STATE_PATH) - self._state_lock = InterprocessFileLock( - self.state_path.with_name(f"{self.state_path.name}.lock") - ) self.persist_enabled = persist - self._has_persisted_state = False - self._state_revision = 0 self.positions: dict[tuple[str, str], Position] = {} self.order_history: list[dict[str, Any]] = [] - self.reconciliation_history: list[dict[str, Any]] = [] self.open_orders: list[dict[str, Any]] = [] self.persistence_error: str | None = None if self.persist_enabled: @@ -51,69 +35,6 @@ def state_healthy(self) -> bool: def _position_key(position: Position) -> tuple[str, str]: return (position.contract_ticker, position.side.lower()) - @staticmethod - def _validate_position(position: Position) -> None: - if ( - not isinstance(position.market_ticker, str) - or not position.market_ticker.strip() - or not isinstance(position.contract_ticker, str) - or not position.contract_ticker.strip() - or position.side not in {"yes", "no"} - or isinstance(position.quantity, bool) - or not isinstance(position.quantity, int) - or position.quantity < 1 - or isinstance(position.avg_price_cents, bool) - or not isinstance(position.avg_price_cents, int) - or not 1 <= position.avg_price_cents <= 100 - or isinstance(position.unrealized_pnl_cents, bool) - or not isinstance(position.unrealized_pnl_cents, int) - ): - raise ValueError("invalid exposure position") - - @staticmethod - def _strict_persisted_position(raw: Any) -> Position: - required = { - "market_ticker", - "contract_ticker", - "side", - "quantity", - "avg_price_cents", - "unrealized_pnl_cents", - } - allowed = required | {"source_ts", "freshness_score"} - if ( - not isinstance(raw, dict) - or not required <= set(raw) <= allowed - or not all( - isinstance(raw[field], str) - for field in ("market_ticker", "contract_ticker", "side") - ) - or any( - isinstance(raw[field], bool) - or not isinstance(raw[field], int) - for field in ( - "quantity", - "avg_price_cents", - "unrealized_pnl_cents", - ) - ) - ): - raise ValueError("persisted position fields or types are invalid") - position = Position.model_validate(raw) - ExposureTracker._validate_position(position) - return position - - @staticmethod - def _strict_int(value: Any, *, minimum: int, maximum: int | None = None) -> int: - if ( - isinstance(value, bool) - or not isinstance(value, int) - or value < minimum - or (maximum is not None and value > maximum) - ): - raise ValueError("persisted exposure integer is invalid") - return value - @staticmethod def _serialize_timestamp(value: Any) -> str: if isinstance(value, datetime): @@ -131,304 +52,66 @@ def _parse_timestamp(value: Any) -> datetime: return parsed.astimezone(timezone.utc) def _load(self) -> None: - try: - with self._state_lock.hold(): - self._load_locked() - except Exception as exc: - self.persistence_error = f"{type(exc).__name__}: {exc}" - - def _load_locked(self, *, require_existing: bool = False) -> bool: if not self.state_path.exists(): - if require_existing or self._has_persisted_state: - self.persistence_error = ( - "FileNotFoundError: persisted exposure state is missing" - ) - return False - self.positions = {} - self.order_history = [] - self.reconciliation_history = [] - self.open_orders = [] - self._state_revision = 0 - return True + return try: data = json.loads(self.state_path.read_text(encoding="utf-8")) if not isinstance(data, dict): raise ValueError("exposure state must be a JSON object") - legacy_fields = { - "positions", - "open_orders", - "order_history", - "updated_at", - } - reconciliation_fields = legacy_fields | { - "reconciliation_history" - } - current_fields = reconciliation_fields | {"state_revision"} - if frozenset(data) not in { - frozenset(legacy_fields), - frozenset(reconciliation_fields), - frozenset(current_fields), - }: - raise ValueError("exposure state fields mismatch") - self._parse_timestamp(data["updated_at"]) - state_revision = self._strict_int( - data.get("state_revision", 0), - minimum=0, - ) positions = data.get("positions", []) orders = data.get("open_orders", []) history = data.get("order_history", []) - reconciliations = data.get("reconciliation_history", []) - if ( - not isinstance(positions, list) - or not isinstance(orders, list) - or not isinstance(history, list) - or not isinstance(reconciliations, list) - ): + if not isinstance(positions, list) or not isinstance(orders, list) or not isinstance(history, list): raise ValueError("exposure state collections must be lists") loaded_positions: dict[tuple[str, str], Position] = {} for raw in positions: - position = self._strict_persisted_position(raw) - key = self._position_key(position) - if key in loaded_positions: - raise ValueError("duplicate persisted position identity") - loaded_positions[key] = position + position = Position.model_validate(raw) + loaded_positions[self._position_key(position)] = position loaded_history = [] for raw in history: if not isinstance(raw, dict): raise ValueError("order history item must be an object") - required_history = {"ts", "market", "size", "price_cents"} - allowed_history = required_history | {"client_order_id"} - if ( - not required_history <= set(raw) <= allowed_history - or not isinstance(raw["market"], str) - or not raw["market"].strip() - or ( - "client_order_id" in raw - and ( - not isinstance(raw["client_order_id"], str) - or not raw["client_order_id"].strip() - ) - ) - ): - raise ValueError("order history fields are invalid") - self._strict_int(raw["size"], minimum=1) - self._strict_int( - raw["price_cents"], - minimum=1, - maximum=99, - ) - loaded_history.append( - {**raw, "ts": self._parse_timestamp(raw["ts"])} - ) + loaded_history.append({**raw, "ts": self._parse_timestamp(raw["ts"])}) loaded_orders: list[dict[str, Any]] = [] - seen_order_identities: set[str] = set() for raw in orders: if not isinstance(raw, dict): raise ValueError("open order item must be an object") order = dict(raw) - required_order = { - "order_id", - "market", - "contract", - "side", - "size", - "price_cents", - "filled_size", - "remaining_size", - "filled_cost_cents", - "state", - } - allowed_order = required_order | { - "client_order_id", - "reserved_at", - "accepted_at", - "last_reconciled_at", - "fee_reserve_cents", - } - if not required_order <= set(order) <= allowed_order: - raise ValueError("persisted open-order fields mismatch") - for field in ( - "order_id", - "market", - "contract", - "side", - "state", - ): - if ( - not isinstance(order[field], str) - or not order[field].strip() - ): - raise ValueError("persisted open-order identity is invalid") - order_id = order["order_id"] - market = order["market"] - contract = order["contract"] - side = order["side"] - state = order["state"] - size = self._strict_int(order["size"], minimum=1) - price = self._strict_int( - order["price_cents"], - minimum=1, - maximum=99, - ) - filled = self._strict_int(order["filled_size"], minimum=0) - remaining = self._strict_int( - order["remaining_size"], - minimum=0, - ) - filled_cost = self._strict_int( - order["filled_cost_cents"], - minimum=0, - ) - fee_reserve = self._strict_int( - order.get( - "fee_reserve_cents", - kalshi_taker_fee_cents( - price, - size, - market, - ), - ), - minimum=0, - ) - client_order_id = order.get("client_order_id") + order_id = str(order.get("order_id") or "").strip() + market = str(order.get("market") or "").strip() + size = int(order.get("size")) + price = int(order.get("price_cents")) + filled = int(order.get("filled_size", 0)) + remaining = int(order.get("remaining_size", size - filled)) if ( - side not in {"yes", "no"} - or state not in _OPEN_ORDER_STATES + not order_id + or not market + or size < 1 + or not (1 <= price <= 99) + or filled < 0 + or remaining < 0 or filled + remaining != size - or filled_cost > filled * 100 - or (filled == 0 and filled_cost != 0) - or ( - client_order_id is not None - and ( - not isinstance(client_order_id, str) - or not client_order_id.strip() - ) - ) ): raise ValueError("invalid persisted open-order reservation") - identities = {order_id} - if client_order_id is not None: - identities.add(client_order_id) - if seen_order_identities & identities: - raise ValueError("duplicate persisted open-order identity") - seen_order_identities.update(identities) order.update({ "order_id": order_id, "market": market, - "contract": contract, - "side": side, "size": size, "price_cents": price, "filled_size": filled, "remaining_size": remaining, - "filled_cost_cents": filled_cost, - "fee_reserve_cents": fee_reserve, - "state": state, + "filled_cost_cents": int( + order.get("filled_cost_cents", filled * price) + ), + "state": str(order.get("state") or "open"), }) loaded_orders.append(order) - loaded_reconciliations: list[dict[str, Any]] = [] - seen_reconciliation_ids: set[str] = set() - for raw in reconciliations: - if not isinstance(raw, dict): - raise ValueError( - "reconciliation history item must be an object" - ) - kind = raw.get("kind") - reconciliation_id = raw.get("reconciliation_id") - if ( - not isinstance(reconciliation_id, str) - or len(reconciliation_id) != 64 - or any( - character not in "0123456789abcdef" - for character in reconciliation_id - ) - or reconciliation_id in seen_reconciliation_ids - ): - raise ValueError( - "reconciliation history identity is invalid" - ) - seen_reconciliation_ids.add(reconciliation_id) - if kind == "terminal_order": - required = { - "kind", - "reconciliation_id", - "order_id", - "client_order_id", - "contract", - "side", - "cumulative_size", - "avg_price_cents", - "terminal_state", - } - if set(raw) != required: - raise ValueError( - "terminal reconciliation fields mismatch" - ) - if ( - raw["side"] not in {"yes", "no"} - or raw["terminal_state"] - not in {"filled", "canceled", "expired", "rejected"} - or not isinstance(raw["order_id"], str) - or not raw["order_id"] - or not isinstance(raw["client_order_id"], str) - or not raw["client_order_id"] - or not isinstance(raw["contract"], str) - or not raw["contract"] - ): - raise ValueError( - "terminal reconciliation identity is invalid" - ) - cumulative = self._strict_int( - raw["cumulative_size"], - minimum=0, - ) - average = raw["avg_price_cents"] - if ( - cumulative == 0 - and average is not None - ) or ( - cumulative > 0 - and ( - isinstance(average, bool) - or not isinstance(average, int) - or not 1 <= average <= 100 - ) - ): - raise ValueError( - "terminal reconciliation price is invalid" - ) - elif kind == "position_close": - if set(raw) != { - "kind", - "reconciliation_id", - "contract", - "side", - } or ( - not isinstance(raw.get("contract"), str) - or not raw["contract"] - or raw.get("side") not in {"yes", "no"} - ): - raise ValueError( - "position-close reconciliation is invalid" - ) - else: - raise ValueError( - "reconciliation history kind is invalid" - ) - loaded_reconciliations.append(dict(raw)) self.positions = loaded_positions self.open_orders = loaded_orders self.order_history = loaded_history - self.reconciliation_history = loaded_reconciliations - self._state_revision = state_revision - self._has_persisted_state = True - self.persistence_error = None - return True except Exception as exc: # A corrupt prior state must block new live orders, not look empty. self.persistence_error = f"{type(exc).__name__}: {exc}" - return False def _payload(self) -> dict[str, Any]: return { @@ -438,222 +121,55 @@ def _payload(self) -> dict[str, Any]: {**order, "ts": self._serialize_timestamp(order["ts"])} for order in self.order_history[-10000:] ], - "reconciliation_history": self.reconciliation_history[-10000:], - "state_revision": self._state_revision, "updated_at": datetime.now(timezone.utc).isoformat(), } - def anchor_head(self) -> tuple[int, str]: - """Return a monotonic revision and canonical semantic-state digest.""" - if self.persist_enabled and not self.refresh_persisted_state(): - raise RuntimeError( - "persisted exposure state is unavailable for anchoring" - ) - payload = { - "schema": EXPOSURE_STATE_ANCHOR_SCHEMA, - "state_revision": self._state_revision, - "positions": sorted( - ( - position.model_dump(mode="json") - for position in self.positions.values() - ), - key=lambda item: ( - str(item["contract_ticker"]), - str(item["side"]), - ), - ), - "open_orders": sorted( - ( - json.loads(canonical_json(order)) - for order in self.open_orders - ), - key=lambda item: ( - str(item.get("client_order_id") or ""), - str(item.get("order_id") or ""), - ), - ), - "order_history": [ - { - **order, - "ts": self._serialize_timestamp(order["ts"]), - } - for order in self.order_history[-10000:] - ], - "reconciliation_history": ( - self.reconciliation_history[-10000:] - ), - } - return self._state_revision, sha256_json(payload) - - def _persist_locked(self) -> bool: + def _persist(self) -> bool: if not self.persist_enabled: return True - tmp = self.state_path.with_name( - f".{self.state_path.name}.{os.getpid()}.{uuid4().hex}.tmp" - ) + tmp = self.state_path.with_suffix(self.state_path.suffix + ".tmp") try: self.state_path.parent.mkdir(parents=True, exist_ok=True) - encoded = json.dumps( - self._payload(), - indent=2, - sort_keys=True, - ) - with tmp.open("w", encoding="utf-8", newline="\n") as handle: - handle.write(encoded) - handle.flush() - os.fsync(handle.fileno()) + tmp.write_text(json.dumps(self._payload(), indent=2, sort_keys=True), encoding="utf-8") os.replace(tmp, self.state_path) - # Flush the replaced file as well. On POSIX, also fsync the parent - # directory so the rename itself is durable. Windows does not - # expose directory handles through os.open, while os.fsync on the - # final file still maps to FlushFileBuffers. - # Windows requires a writable handle for FlushFileBuffers via - # ``os.fsync``; opening read-only raises ``EBADF`` even though no - # additional bytes are written here. - with self.state_path.open("r+b") as handle: - os.fsync(handle.fileno()) - if os.name != "nt": - directory_fd = os.open( - self.state_path.parent, - os.O_RDONLY, - ) - try: - os.fsync(directory_fd) - finally: - os.close(directory_fd) - self._has_persisted_state = True self.persistence_error = None return True except Exception as exc: self.persistence_error = f"{type(exc).__name__}: {exc}" return False - finally: - try: - tmp.unlink(missing_ok=True) - except OSError: - pass - - def _mutate_persisted_state( - self, - mutation: Callable[[], bool], - ) -> bool: - if self.persistence_error is not None: - return False - if not self.persist_enabled: - if not mutation(): - return False - self._state_revision += 1 - return True - try: - with self._state_lock.hold(): - if not self._load_locked(): - return False - if not mutation(): - return False - self._state_revision += 1 - return self._persist_locked() - except Exception as exc: - self.persistence_error = f"{type(exc).__name__}: {exc}" - return False - - def refresh_persisted_state( - self, - *, - require_existing: bool = False, - ) -> bool: - if not self.persist_enabled: - return self.persistence_error is None - if self.persistence_error is not None: - return False - try: - with self._state_lock.hold(): - return self._load_locked( - require_existing=require_existing - ) - except Exception as exc: - self.persistence_error = f"{type(exc).__name__}: {exc}" - return False def verify_persistence(self) -> bool: - """Reload then replace only the exact newest cross-process state.""" + """Preflight the state sink before any broker submission.""" if self.persistence_error is not None: # Never overwrite a corrupt/unknown prior position book with an # empty optimistic one. Resolution requires an operator repair. return False - if not self.persist_enabled: - return True - try: - with self._state_lock.hold(): - if not self._load_locked(): - return False - return self._persist_locked() - except Exception as exc: - self.persistence_error = f"{type(exc).__name__}: {exc}" - return False - - def record_order( - self, - market_ticker: str, - size: int, - price_cents: int, - ) -> None: - if ( - not isinstance(market_ticker, str) - or not market_ticker.strip() - or isinstance(size, bool) - or not isinstance(size, int) - or size < 1 - or isinstance(price_cents, bool) - or not isinstance(price_cents, int) - or not 1 <= price_cents <= 99 - ): - raise ValueError("invalid order history record") - - def mutation() -> bool: - self.order_history.append({ - "ts": datetime.now(timezone.utc), - "market": market_ticker, - "size": size, - "price_cents": price_cents, - }) - return True - - self._mutate_persisted_state(mutation) - - def update_position(self, position: Position) -> None: - self._validate_position(position) - - def mutation() -> bool: - self.positions[self._position_key(position)] = position - return True - - self._mutate_persisted_state(mutation) - - def remove_position( - self, - ticker: str, - side: str | None = None, - ) -> None: + return self._persist() + + def record_order(self, market_ticker: str, size: int, price_cents: int): + self.order_history.append({ + "ts": datetime.now(timezone.utc), + "market": market_ticker, + "size": size, + "price_cents": price_cents, + }) + self._persist() + + def update_position(self, position: Position): + self.positions[self._position_key(position)] = position + self._persist() + + def remove_position(self, ticker: str, side: str | None = None): normalized_side = side.lower() if side else None - - def mutation() -> bool: - self.positions = { - key: position - for key, position in self.positions.items() - if not ( - ( - position.contract_ticker == ticker - or position.market_ticker == ticker - ) - and ( - normalized_side is None - or position.side.lower() == normalized_side - ) - ) - } - return True - - self._mutate_persisted_state(mutation) + self.positions = { + key: position + for key, position in self.positions.items() + if not ( + (position.contract_ticker == ticker or position.market_ticker == ticker) + and (normalized_side is None or position.side.lower() == normalized_side) + ) + } + self._persist() def add_open_order( self, @@ -664,50 +180,26 @@ def add_open_order( *, contract_ticker: str | None = None, side: str | None = None, - ) -> None: - contract = contract_ticker or market_ticker - if ( - not isinstance(order_id, str) - or not order_id.strip() - or not isinstance(market_ticker, str) - or not market_ticker.strip() - or not isinstance(contract, str) - or not contract.strip() - or side not in {"yes", "no"} - or isinstance(size, bool) - or not isinstance(size, int) - or size < 1 - or isinstance(price_cents, bool) - or not isinstance(price_cents, int) - or not 1 <= price_cents <= 99 - ): + ): + if not order_id or int(size) < 1 or not (1 <= int(price_cents) <= 99): raise ValueError("invalid open-order reservation") - - def mutation() -> bool: - self.open_orders = [ - order for order in self.open_orders - if order.get("order_id") != order_id - ] - self.open_orders.append({ - "order_id": order_id, - "market": market_ticker, - "contract": contract, - "side": side, - "size": int(size), - "remaining_size": int(size), - "filled_size": 0, - "filled_cost_cents": 0, - "fee_reserve_cents": kalshi_taker_fee_cents( - int(price_cents), - int(size), - market_ticker, - ), - "price_cents": int(price_cents), - "state": "open", - }) - return True - - self._mutate_persisted_state(mutation) + self.open_orders = [ + order for order in self.open_orders + if order.get("order_id") != order_id + ] + self.open_orders.append({ + "order_id": order_id, + "market": market_ticker, + "contract": contract_ticker or market_ticker, + "side": side, + "size": int(size), + "remaining_size": int(size), + "filled_size": 0, + "filled_cost_cents": 0, + "price_cents": int(price_cents), + "state": "open", + }) + self._persist() def reserve_order_submission( self, @@ -725,80 +217,45 @@ def reserve_order_submission( reservation first ensures that process failure or an ambiguous transport result cannot make the next order assume zero exposure. """ + if self.persistence_error is not None: + return False if ( - not isinstance(client_order_id, str) - or not client_order_id.strip() - or not isinstance(market_ticker, str) - or not market_ticker.strip() - or not isinstance(contract_ticker, str) - or not contract_ticker.strip() - or side not in {"yes", "no"} - or isinstance(size, bool) - or not isinstance(size, int) - or size < 1 - or isinstance(price_cents, bool) - or not isinstance(price_cents, int) - or not 1 <= price_cents <= 99 + not client_order_id + or int(size) < 1 + or not (1 <= int(price_cents) <= 99) ): self.persistence_error = "invalid order-submission reservation" return False - - def mutation() -> bool: - if any( - order.get("order_id") == client_order_id - or order.get("client_order_id") == client_order_id - for order in self.open_orders - ): - self.persistence_error = "duplicate client order id" - return False - now = datetime.now(timezone.utc) - self.order_history.append({ - "ts": now, - "market": market_ticker, - "size": int(size), - "price_cents": int(price_cents), - "client_order_id": client_order_id, - }) - self.open_orders.append({ - "order_id": client_order_id, - "client_order_id": client_order_id, - "market": market_ticker, - "contract": contract_ticker or market_ticker, - "side": side, - "size": int(size), - "remaining_size": int(size), - "filled_size": 0, - "filled_cost_cents": 0, - "fee_reserve_cents": kalshi_taker_fee_cents( - int(price_cents), - int(size), - market_ticker, - ), - "price_cents": int(price_cents), - "state": "submitting", - "reserved_at": now.isoformat(), - }) - return True - - return self._mutate_persisted_state(mutation) - - def submission_record( - self, - client_order_id: str, - ) -> dict[str, Any] | None: - """Return an existing durable/ambiguous submission without mutating it.""" - normalized = str(client_order_id).strip() - if not normalized: - return None - if self.persist_enabled and not self.refresh_persisted_state(): - return None - for order in self.open_orders: - if ( - str(order.get("order_id") or "") == normalized - or str(order.get("client_order_id") or "") == normalized - ): - return dict(order) - return None + if any( + order.get("order_id") == client_order_id + or order.get("client_order_id") == client_order_id + for order in self.open_orders + ): + self.persistence_error = "duplicate client order id" + return False + now = datetime.now(timezone.utc) + self.order_history.append({ + "ts": now, + "market": market_ticker, + "size": int(size), + "price_cents": int(price_cents), + "client_order_id": client_order_id, + }) + self.open_orders.append({ + "order_id": client_order_id, + "client_order_id": client_order_id, + "market": market_ticker, + "contract": contract_ticker or market_ticker, + "side": side, + "size": int(size), + "remaining_size": int(size), + "filled_size": 0, + "filled_cost_cents": 0, + "price_cents": int(price_cents), + "state": "submitting", + "reserved_at": now.isoformat(), + }) + return self._persist() def confirm_open_order( self, @@ -806,65 +263,32 @@ def confirm_open_order( broker_order_id: str, ) -> bool: """Bind a pre-transport reservation to the broker order id.""" - if ( - not isinstance(client_order_id, str) - or not client_order_id.strip() - or not isinstance(broker_order_id, str) - or not broker_order_id.strip() - ): + if self.persistence_error is not None or not broker_order_id: return False - - def mutation() -> bool: - if any( - broker_order_id - in { - str(order.get("order_id") or ""), - str(order.get("client_order_id") or ""), - } - and client_order_id - not in { - str(order.get("order_id") or ""), - str(order.get("client_order_id") or ""), - } - for order in self.open_orders + for order in self.open_orders: + if ( + order.get("order_id") == client_order_id + or order.get("client_order_id") == client_order_id ): - self.persistence_error = "duplicate broker order id" - return False - for order in self.open_orders: - if ( - order.get("order_id") == client_order_id - or order.get("client_order_id") == client_order_id - ): - order["client_order_id"] = client_order_id - order["order_id"] = broker_order_id - order["state"] = "open" - order["accepted_at"] = ( - datetime.now(timezone.utc).isoformat() - ) - return True - self.persistence_error = ( - "accepted order has no durable reservation" - ) - return False - - return self._mutate_persisted_state(mutation) + order["client_order_id"] = client_order_id + order["order_id"] = broker_order_id + order["state"] = "open" + order["accepted_at"] = datetime.now(timezone.utc).isoformat() + return self._persist() + self.persistence_error = "accepted order has no durable reservation" + return False def mark_order_outcome_unknown(self, client_order_id: str) -> bool: """Keep an ambiguous submission reserved until reconciliation.""" - def mutation() -> bool: - for order in self.open_orders: - if ( - order.get("order_id") == client_order_id - or order.get("client_order_id") == client_order_id - ): - order["state"] = "submit_outcome_unknown" - return True - self.persistence_error = ( - "unknown submit outcome has no reservation" - ) - return False - - return self._mutate_persisted_state(mutation) + for order in self.open_orders: + if ( + order.get("order_id") == client_order_id + or order.get("client_order_id") == client_order_id + ): + order["state"] = "submit_outcome_unknown" + return self._persist() + self.persistence_error = "unknown submit outcome has no reservation" + return False def record_cumulative_fill( self, @@ -873,7 +297,6 @@ def record_cumulative_fill( avg_price_cents: int | None, *, terminal_state: str | None = None, - reconciliation_id: str | None = None, ) -> bool: """Apply a broker-witnessed cumulative fill without double counting. @@ -882,74 +305,8 @@ def record_cumulative_fill( unfilled remainder at the submitted LIMIT. Filled/canceled terminal states release only the remainder that the broker has resolved. """ - return self._mutate_persisted_state( - lambda: self._record_cumulative_fill_in_memory( - order_id, - cumulative_size, - avg_price_cents, - terminal_state=terminal_state, - reconciliation_id=reconciliation_id, - ) - ) - - def _record_cumulative_fill_in_memory( - self, - order_id: str, - cumulative_size: int, - avg_price_cents: int | None, - *, - terminal_state: str | None, - reconciliation_id: str | None, - ) -> bool: - normalized_reconciliation_id: str | None = None - if reconciliation_id is not None: - normalized_reconciliation_id = str(reconciliation_id) - if ( - len(normalized_reconciliation_id) != 64 - or any( - character not in "0123456789abcdef" - for character in normalized_reconciliation_id - ) - ): - self.persistence_error = ( - "terminal reconciliation identity is invalid" - ) - return False - prior_reconciliation = next( - ( - item - for item in self.reconciliation_history - if item.get("reconciliation_id") - == normalized_reconciliation_id - ), - None, - ) - expected_terminal = { - "kind": "terminal_order", - "reconciliation_id": normalized_reconciliation_id, - "order_id": str(order_id), - "client_order_id": "", - "contract": "", - "side": "", - "cumulative_size": int(cumulative_size), - "avg_price_cents": avg_price_cents, - "terminal_state": str(terminal_state or "").lower(), - } - if prior_reconciliation is not None: - comparable = { - **expected_terminal, - "client_order_id": prior_reconciliation.get( - "client_order_id" - ), - "contract": prior_reconciliation.get("contract"), - "side": prior_reconciliation.get("side"), - } - if prior_reconciliation == comparable: - return True - self.persistence_error = ( - "terminal reconciliation identity conflict" - ) - return False + if self.persistence_error is not None: + return False order = next( ( item for item in self.open_orders @@ -970,13 +327,7 @@ def _record_cumulative_fill_in_memory( self.persistence_error = "malformed open order during fill reconcile" return False terminal = str(terminal_state or "").lower() or None - if terminal not in { - None, - "filled", - "canceled", - "expired", - "rejected", - }: + if terminal not in {None, "filled", "canceled", "expired"}: self.persistence_error = "invalid terminal fill state" return False if not (prior_size <= cumulative_size <= original_size): @@ -1046,213 +397,63 @@ def _record_cumulative_fill_in_memory( ) order["last_reconciled_at"] = datetime.now(timezone.utc).isoformat() if terminal is not None: - if normalized_reconciliation_id is not None: - self.reconciliation_history.append( - { - "kind": "terminal_order", - "reconciliation_id": ( - normalized_reconciliation_id - ), - # Preserve the caller's lookup identity, not the - # broker-rebound id. A restart may replay the same - # witness by proposal/client id after the open order - # was removed, so this value must remain stable across - # the first application and every idempotent replay. - "order_id": str(order_id), - "client_order_id": str( - order.get("client_order_id") or order_id - ), - "contract": str(order.get("contract") or ""), - "side": str(order.get("side") or ""), - "cumulative_size": cumulative_size, - "avg_price_cents": avg_price_cents, - "terminal_state": terminal, - } - ) self.open_orders = [item for item in self.open_orders if item is not order] - return True - - def record_position_close( - self, - ticker: str, - side: str, - *, - reconciliation_id: str, - ) -> bool: - """Persist one idempotent settlement-backed position removal.""" - normalized_id = str(reconciliation_id) - normalized_side = str(side).lower() - if ( - len(normalized_id) != 64 - or any( - character not in "0123456789abcdef" - for character in normalized_id - ) - or not isinstance(ticker, str) - or not ticker - or normalized_side not in {"yes", "no"} - ): - self.persistence_error = ( - "position-close reconciliation identity is invalid" - ) - return False - - expected = { - "kind": "position_close", - "reconciliation_id": normalized_id, - "contract": ticker, - "side": normalized_side, - } + return self._persist() - def mutation() -> bool: - prior = next( - ( - item - for item in self.reconciliation_history - if item.get("reconciliation_id") == normalized_id - ), - None, - ) - if prior is not None: - if prior == expected: - return True - self.persistence_error = ( - "position-close reconciliation identity conflict" - ) - return False - self.positions.pop((ticker, normalized_side), None) - self.reconciliation_history.append(expected) - return True - - return self._mutate_persisted_state(mutation) - - def remove_open_order(self, order_id: str) -> None: - def mutation() -> bool: - self.open_orders = [ - order for order in self.open_orders - if order.get("order_id") != order_id - and order.get("client_order_id") != order_id - ] - return True - - self._mutate_persisted_state(mutation) - - def _refresh_for_risk_read(self) -> bool: - return ( - self.persistence_error is None - and ( - not self.persist_enabled - or self.refresh_persisted_state(require_existing=True) - ) - ) - - def _bounded_exposure( - self, - positions: Any, - orders: Any, - ) -> int: - """Calculate notional or return a cap-breaking fail-closed sentinel.""" - try: - total = 0 - for position in positions: - self._validate_position(position) - total += position.quantity * position.avg_price_cents - for order in orders: - remaining = order.get("remaining_size") - price = order.get("price_cents") - if ( - isinstance(remaining, bool) - or not isinstance(remaining, int) - or remaining < 0 - or isinstance(price, bool) - or not isinstance(price, int) - or not 1 <= price <= 99 - ): - raise ValueError("invalid open-order risk fields") - total += remaining * price - fee_reserve = order.get("fee_reserve_cents", 0) - if ( - isinstance(fee_reserve, bool) - or not isinstance(fee_reserve, int) - or fee_reserve < 0 - ): - raise ValueError( - "invalid open-order fee reservation" - ) - total += fee_reserve - if total < 0: - raise ValueError("negative aggregate exposure") - return total - except (AttributeError, TypeError, ValueError) as exc: - self.persistence_error = ( - f"{type(exc).__name__}: invalid exposure risk state" - ) - return _FAIL_CLOSED_EXPOSURE_CENTS + def remove_open_order(self, order_id: str): + self.open_orders = [ + order for order in self.open_orders + if order.get("order_id") != order_id + and order.get("client_order_id") != order_id + ] + self._persist() def total_exposure_cents(self) -> int: - if not self._refresh_for_risk_read(): - return _FAIL_CLOSED_EXPOSURE_CENTS - return self._bounded_exposure( - self.positions.values(), - self.open_orders, + positions = sum( + p.quantity * p.avg_price_cents for p in self.positions.values() + ) + reservations = sum( + int(order.get("remaining_size", order.get("size", 0))) + * int(order.get("price_cents", 0)) + for order in self.open_orders ) + return positions + reservations def market_exposure_cents(self, ticker: str) -> int: - if not self._refresh_for_risk_read(): - return _FAIL_CLOSED_EXPOSURE_CENTS - return self._bounded_exposure( - ( - position - for position in self.positions.values() - if position.market_ticker == ticker - ), - ( - order - for order in self.open_orders - if order.get("market") == ticker - ), + positions = sum( + position.quantity * position.avg_price_cents + for position in self.positions.values() + if position.market_ticker == ticker + ) + reservations = sum( + int(order.get("remaining_size", order.get("size", 0))) + * int(order.get("price_cents", 0)) + for order in self.open_orders + if order.get("market") == ticker ) + return positions + reservations def correlated_exposure_cents(self, ticker: str) -> int: - if not self._refresh_for_risk_read(): - return _FAIL_CLOSED_EXPOSURE_CENTS # Event-family proxy: Kalshi event/series prefix before the first '-'. prefix = ticker.split("-")[0].upper() - return self._bounded_exposure( - ( - position - for position in self.positions.values() - if position.market_ticker.upper().split("-")[0] == prefix - ), - ( - order - for order in self.open_orders - if str(order.get("market", "")).upper().split("-")[0] - == prefix - ), + positions = sum( + p.quantity * p.avg_price_cents + for p in self.positions.values() + if p.market_ticker.upper().split("-")[0] == prefix ) + reservations = sum( + int(order.get("remaining_size", order.get("size", 0))) + * int(order.get("price_cents", 0)) + for order in self.open_orders + if str(order.get("market", "")).upper().split("-")[0] == prefix + ) + return positions + reservations def orders_last_hour(self) -> int: - if not self._refresh_for_risk_read(): - return _FAIL_CLOSED_EXPOSURE_CENTS cutoff = datetime.now(timezone.utc) - timedelta(hours=1) - try: - return len( - [ - order - for order in self.order_history - if self._parse_timestamp(order["ts"]) > cutoff - ] - ) - except (KeyError, TypeError, ValueError) as exc: - self.persistence_error = ( - f"{type(exc).__name__}: invalid order history state" - ) - return _FAIL_CLOSED_EXPOSURE_CENTS + return len([o for o in self.order_history if self._parse_timestamp(o["ts"]) > cutoff]) def open_markets(self) -> int: - if not self._refresh_for_risk_read(): - return _FAIL_CLOSED_EXPOSURE_CENTS markets = {position.market_ticker for position in self.positions.values()} markets.update( str(order["market"]) @@ -1262,26 +463,8 @@ def open_markets(self) -> int: return len(markets) def open_order_count(self) -> int: - if not self._refresh_for_risk_read(): - return _FAIL_CLOSED_EXPOSURE_CENTS return len(self.open_orders) - def client_order_id_for(self, order_id: str) -> str | None: - """Resolve the durable proposal identity before terminal removal.""" - normalized = str(order_id).strip() - if not normalized: - return None - if self.persist_enabled and not self.refresh_persisted_state(): - return None - for order in self.open_orders: - if ( - str(order.get("order_id") or "") == normalized - or str(order.get("client_order_id") or "") == normalized - ): - candidate = str(order.get("client_order_id") or "").strip() - return candidate or None - return None - _PERSISTENT_TRACKER: ExposureTracker | None = None diff --git a/live_firewall/firewall.py b/live_firewall/firewall.py index 5d388a73..466a4cd8 100644 --- a/live_firewall/firewall.py +++ b/live_firewall/firewall.py @@ -1,14 +1,12 @@ import hashlib -import inspect import json import os -import secrets from collections.abc import Mapping from dataclasses import dataclass from datetime import datetime, timezone, timedelta from decimal import Decimal from pathlib import Path -from typing import Any, Callable, Optional +from typing import Any, Optional from core.state import STATE from core.caps_authority import evaluate_caps_authority from core.config_loader import load_caps @@ -32,7 +30,6 @@ verify_model_influence_attestation, ) from forecasting.model_probability_authority import ModelProbabilityAuthorityRegistry -from live_firewall.dumbmoney_capital import CapitalEnvelopeAdapter REJECTED_ADAPTERS: set[str] = set() @@ -244,8 +241,6 @@ def __init__( require_autonomy_risk_state: bool = False, require_canary_readiness: bool = False, model_authority_registry: ModelProbabilityAuthorityRegistry | None = None, - capital_envelope_adapter: CapitalEnvelopeAdapter | None = None, - core_submission_authority: Callable[[], bool] | None = None, ): self.client = kalshi_client self.exposure = exposure_tracker @@ -256,16 +251,6 @@ def __init__( self.model_authority_registry = ( model_authority_registry or ModelProbabilityAuthorityRegistry() ) - # Additional deny-only DumbMoney bound. Absence preserves the - # standalone Dummy authority model; presence makes a valid signed grant - # mandatory without replacing any existing local gate. - self.capital_envelope_adapter = capital_envelope_adapter - if ( - core_submission_authority is not None - and not callable(core_submission_authority) - ): - raise TypeError("core_submission_authority must be callable") - self.core_submission_authority = core_submission_authority self.autonomy_risk_state_path = autonomy_risk_state_path or Path( os.environ.get( "DUMMY_AUTONOMY_LIVE_RISK_STATE_PATH", @@ -458,374 +443,13 @@ async def _trusted_sink_orderbook( def _mandatory_submit_authority( self, req: LiveOrderRequest, - *, - reservation_held: bool = False, - trusted_orderbook: OrderBook | None = None, - forecast: Forecast | None = None, ) -> FirewallVerdict: """Recheck every non-optional real-submit authority gate.""" - now = datetime.now(timezone.utc) - if ( - req.expiration_ts is not None - and req.expiration_ts <= int(now.timestamp()) - ): - return FirewallVerdict( - allow=False, - reason="Limit order expiry is not in the future", - rejected_by="order_expiry", - ) - if ( - self.capital_envelope_adapter is not None - and req.liquidity_role == "maker" - and req.expiration_ts is None - ): - return FirewallVerdict( - allow=False, - reason="Maker order lacks exchange-enforced expiration", - rejected_by="order_expiry", - ) - if self.capital_envelope_adapter is not None: - if self.core_submission_authority is None: - return FirewallVerdict( - allow=False, - reason="Current DumbMoney Core control authority is required", - rejected_by="core_command_authority", - ) - try: - core_allows = self.core_submission_authority() - except Exception: - core_allows = False - if core_allows is not True: - return FirewallVerdict( - allow=False, - reason="DumbMoney Core control authority is not current", - rejected_by="core_command_authority", - ) - if not STATE.refresh_persisted_state(): - return FirewallVerdict( - allow=False, - reason="Persisted risk/safety state unavailable", - rejected_by="risk_state", - ) - if STATE.kill_switch.active: - return FirewallVerdict( - allow=False, - reason="Kill switch active", - rejected_by="kill_switch", - ) - if STATE.emergency_stop.active: - return FirewallVerdict( - allow=False, - reason="Emergency stop active", - rejected_by="emergency_stop", - ) - if STATE.persistence_error or not STATE.verify_persistence(): - return FirewallVerdict( - allow=False, - reason="Persisted daily-loss state unavailable", - rejected_by="daily_loss_state", - ) - if ( - not self.exposure.state_healthy - or not self.exposure.verify_persistence() - ): - return FirewallVerdict( - allow=False, - reason="Persisted exposure state unavailable", - rejected_by="exposure_state", - ) - caps = load_caps() - if STATE.daily_loss_cents >= caps.max_daily_loss_cents: - return FirewallVerdict( - allow=False, - reason="Daily loss cap exceeded", - rejected_by="daily_loss_cap", - ) - if reservation_held: - order_value = req.price_cents * req.size - if order_value > caps.max_single_order_cents: - return FirewallVerdict( - allow=False, - reason="Single order cap exceeded after reservation", - rejected_by="single_order_cap", - ) - if ( - self.exposure.market_exposure_cents( - req.market_ticker - ) - > caps.max_market_exposure_cents - ): - return FirewallVerdict( - allow=False, - reason="Market exposure cap exceeded after reservation", - rejected_by="market_exposure_cap", - ) - if ( - self.exposure.total_exposure_cents() - > caps.max_total_live_exposure_cents - ): - return FirewallVerdict( - allow=False, - reason="Total exposure cap exceeded after reservation", - rejected_by="total_exposure_cap", - ) - if ( - self.exposure.correlated_exposure_cents( - req.market_ticker - ) - > caps.max_correlated_exposure_cents - ): - return FirewallVerdict( - allow=False, - reason=( - "Correlated exposure cap exceeded after reservation" - ), - rejected_by="correlated_exposure_cap", - ) - if self.exposure.open_markets() > caps.max_open_markets: - return FirewallVerdict( - allow=False, - reason="Max open markets exceeded after reservation", - rejected_by="open_markets", - ) - if ( - self.exposure.orders_last_hour() - > caps.max_orders_per_hour - ): - return FirewallVerdict( - allow=False, - reason="Order frequency cap exceeded after reservation", - rejected_by="frequency_cap", - ) - if ( - self.exposure.open_order_count() - > caps.max_orders_per_hour - ): - return FirewallVerdict( - allow=False, - reason=( - "Open order count exceeded after reservation" - ), - rejected_by="open_order_cap", - ) - if trusted_orderbook is not None: - freshness_clocks = [trusted_orderbook.timestamp] - if trusted_orderbook.received_at is not None: - freshness_clocks.append(trusted_orderbook.received_at) - if trusted_orderbook.source_ts is not None: - freshness_clocks.append(trusted_orderbook.source_ts) - if any( - stamp.tzinfo is None - or stamp < now - timedelta(seconds=30) - or stamp > now + timedelta(seconds=5) - for stamp in freshness_clocks - ): - return FirewallVerdict( - allow=False, - reason="Trusted broker depth expired before submission", - rejected_by="stale_data", - ) - caps = load_caps() - if not market_is_allowlisted(req.market_ticker, caps): - return FirewallVerdict( - allow=False, - reason="Market not allowlisted at final submit", - rejected_by="market_allowlist", - ) - if ( - req.side not in {"yes", "no"} - or req.size < 1 - or not 1 <= req.price_cents <= 99 - ): - return FirewallVerdict( - allow=False, - reason="Invalid final limit-order schema", - rejected_by="order_schema", - ) - if ( - trusted_orderbook.market_ticker != req.market_ticker - or trusted_orderbook.contract_ticker != req.contract_ticker - or not trusted_orderbook.bids - or not trusted_orderbook.asks - or any( - level.size <= 0 or not 1 <= level.price <= 99 - for level in ( - trusted_orderbook.bids + trusted_orderbook.asks - ) - ) - ): - return FirewallVerdict( - allow=False, - reason="Trusted broker depth failed final schema binding", - rejected_by="context_integrity", - ) - side_bids, side_asks = self._side_book_ladders( - req, - trusted_orderbook, - ) - if not side_bids or not side_asks: - return FirewallVerdict( - allow=False, - reason="Trusted side-specific depth is unavailable", - rejected_by="liquidity", - ) - best_bid = side_bids[0][0] - best_ask = side_asks[0][0] - spread = best_ask - best_bid - total_liquidity = sum( - level.size - for level in ( - trusted_orderbook.bids + trusted_orderbook.asks - ) - ) - if spread <= 0 or spread > caps.max_spread_cents: - return FirewallVerdict( - allow=False, - reason="Trusted spread violates current policy", - rejected_by="spread", - ) - if total_liquidity < caps.min_liquidity: - return FirewallVerdict( - allow=False, - reason="Trusted liquidity violates current policy", - rejected_by="liquidity", - ) - if req.liquidity_role == "maker": - if not best_bid <= req.price_cents < best_ask: - return FirewallVerdict( - allow=False, - reason="Maker order is not passive at final submit", - rejected_by="execution_role", - ) - else: - executable_size = sum( - size - for price, size in side_asks - if price <= req.price_cents - ) - if ( - req.price_cents < best_ask - or executable_size < req.size - ): - return FirewallVerdict( - allow=False, - reason="Final taker depth cannot execute the request", - rejected_by="executable_depth", - ) - if forecast is not None: - if ( - forecast.market_ticker != req.market_ticker - or forecast.contract_ticker != req.contract_ticker - or forecast.proof_reference - != req.forecast_proof_reference - ): - return FirewallVerdict( - allow=False, - reason="Forecast identity changed before final submit", - rejected_by="context_integrity", - ) - net_ev = self._net_ev_verdict(req, forecast, caps) - if not net_ev.allow: - return net_ev - if forecast.settlement_risk_score > Decimal("0.8"): - return FirewallVerdict( - allow=False, - reason="Settlement risk too high at final submit", - rejected_by="settlement_risk", - ) - model_influence = self._model_influence_verdict( - req, - forecast, - ) - if not model_influence.allow: - return model_influence risk_verdict = self._autonomy_risk_verdict(req, required=True) if not risk_verdict.allow: return risk_verdict - capital_verdict = self._capital_envelope_verdict( - req, - reservation_held=reservation_held, - ) - if not capital_verdict.allow: - return capital_verdict return self.live_authority_verdict() - def _capital_envelope_verdict( - self, - req: LiveOrderRequest, - *, - reservation_held: bool = False, - ) -> FirewallVerdict: - """Revalidate the optional signed external ceiling. - - The adapter can only reject or further reduce locally permitted risk. - It is deliberately evaluated after Dummy's own caps in ``evaluate``; - the central sink also calls it from mandatory authority checks so a - replaced preflight cannot bypass it. - """ - fields_present = any( - value is not None - for value in ( - req.capital_envelope_id, - req.capital_strategy_hash, - req.capital_passport_hash, - req.capital_promotion_hash, - req.capital_fencing_generation, - ) - ) - if self.capital_envelope_adapter is None: - if fields_present: - return FirewallVerdict( - allow=False, - reason="DumbMoney capital adapter unavailable", - rejected_by="capital_adapter", - ) - return FirewallVerdict( - allow=True, - reason="Standalone Dummy authority; no external capital adapter", - ) - if not all( - value is not None - for value in ( - req.capital_envelope_id, - req.capital_strategy_hash, - req.capital_passport_hash, - req.capital_promotion_hash, - req.capital_fencing_generation, - ) - ): - return FirewallVerdict( - allow=False, - reason="Signed DumbMoney capital binding is incomplete", - rejected_by="capital_envelope", - ) - try: - verdict = self.capital_envelope_adapter.evaluate_request( - req, - current_daily_loss_cents=max(0, int(STATE.daily_loss_cents)), - current_local_total_exposure_cents=( - self.exposure.total_exposure_cents() - ), - current_local_correlated_exposure_cents=( - self.exposure.correlated_exposure_cents( - req.market_ticker - ) - ), - current_local_open_orders=self.exposure.open_order_count(), - current_request_locally_reserved=reservation_held, - ) - except Exception as exc: - return FirewallVerdict( - allow=False, - reason=f"DumbMoney capital state unavailable:{type(exc).__name__}", - rejected_by="capital_envelope", - ) - return FirewallVerdict( - allow=verdict.allow, - reason=verdict.reason, - rejected_by=verdict.rejected_by, - ) - def _model_influence_verdict( self, req: LiveOrderRequest, @@ -989,15 +613,6 @@ def fail(by: str, reason: str) -> FirewallVerdict: return fail("order_schema", "Invalid limit order side, price, or size") if req.expiration_ts is not None and req.expiration_ts <= int(datetime.now(timezone.utc).timestamp()): return fail("order_expiry", "Limit order expiry is not in the future") - if ( - self.capital_envelope_adapter is not None - and req.liquidity_role == "maker" - and req.expiration_ts is None - ): - return fail( - "order_expiry", - "Maker order lacks exchange-enforced expiration", - ) if not os.environ.get("KALSHI_API_KEY_ID"): return fail("secrets", "API key missing") allowed = get_allowed_adapter_names() @@ -1092,15 +707,6 @@ def fail(by: str, reason: str) -> FirewallVerdict: return fail("frequency_cap", "Order frequency cap exceeded") if self.exposure.open_order_count() >= caps.max_orders_per_hour: return fail("open_order_cap", "Open order count exceeded") - # External capital grants are additional ceilings only. Dummy's local - # cap, exposure, loss, frequency, and order-count checks above always - # run first and can never be widened by the grant. - capital_verdict = self._capital_envelope_verdict(req) - if not capital_verdict.allow: - return fail( - capital_verdict.rejected_by or "capital_envelope", - capital_verdict.reason, - ) if forecast.settlement_risk_score > Decimal("0.8"): return fail("settlement_risk", "Settlement risk too high") model_influence_verdict = self._model_influence_verdict(req, forecast) @@ -1120,95 +726,24 @@ def _live_submit_enabled(self) -> bool: return is_live_submit_armed() def _build_order(self, req: LiveOrderRequest) -> dict[str, Any]: - # Create Order V2 uses one YES-denominated book. Buying NO is an ask - # at the complementary YES price. Fixed-point strings are constructed - # without binary floating-point conversion. - yes_price_cents = ( - req.price_cents if req.side == "yes" else 100 - req.price_cents - ) - maker = req.liquidity_role == "maker" + # trade-api/v2 CreateOrder body: the limit price is side-specific + # (yes_price/no_price) and client_order_id is required. order: dict[str, Any] = { "ticker": req.contract_ticker, + "side": req.side, + "action": "buy", + "type": "limit", + "count": req.size, "client_order_id": req.proposal_id, - "side": "bid" if req.side == "yes" else "ask", - "count": f"{req.size}.00", - "price": f"0.{yes_price_cents:02d}00", - "time_in_force": ( - "good_till_canceled" if maker else "fill_or_kill" - ), - "self_trade_prevention_type": "taker_at_cross", - "post_only": maker, - "cancel_order_on_pause": True, - "reduce_only": False, - "subaccount": 0, - "exchange_index": 0, } - if maker and req.expiration_ts is not None: - order["expiration_time"] = req.expiration_ts + if req.side == "no": + order["no_price"] = req.price_cents + else: + order["yes_price"] = req.price_cents + if req.expiration_ts is not None: + order["expiration_ts"] = req.expiration_ts return order - @staticmethod - def _validate_v2_create_response( - response: Any, - *, - request: LiveOrderRequest, - ) -> str: - """Validate the current Create Order V2 acknowledgement shape.""" - if not isinstance(response, Mapping): - raise ValueError("Create Order V2 response is not an object") - required = {"order_id", "fill_count", "remaining_count", "ts_ms"} - allowed = required | { - "client_order_id", - "average_fill_price", - "average_fee_paid", - } - if not required <= set(response) <= allowed: - raise ValueError("Create Order V2 response fields mismatch") - order_id = response["order_id"] - if not isinstance(order_id, str) or not order_id.strip(): - raise ValueError("Create Order V2 order_id is invalid") - client_order_id = response.get("client_order_id") - if ( - client_order_id is not None - and client_order_id != request.proposal_id - ): - raise ValueError( - "Create Order V2 client_order_id differs from proposal" - ) - try: - fill_count = Decimal(response["fill_count"]) - remaining_count = Decimal(response["remaining_count"]) - except Exception as exc: - raise ValueError( - "Create Order V2 counts are not fixed-point values" - ) from exc - if ( - not isinstance(response["fill_count"], str) - or not isinstance(response["remaining_count"], str) - or not fill_count.is_finite() - or not remaining_count.is_finite() - or fill_count < 0 - or remaining_count < 0 - or fill_count != fill_count.to_integral_value() - or remaining_count != remaining_count.to_integral_value() - or fill_count + remaining_count > Decimal(request.size) - ): - raise ValueError("Create Order V2 counts are invalid") - ts_ms = response["ts_ms"] - if ( - isinstance(ts_ms, bool) - or not isinstance(ts_ms, int) - or ts_ms < 1 - ): - raise ValueError("Create Order V2 ts_ms is invalid") - # Any immediate fill or canceled remainder needs broker reconciliation - # before local open-order state can be finalized. - if fill_count != 0 or remaining_count != Decimal(request.size): - raise ValueError( - "Create Order V2 acknowledgement requires fill reconciliation" - ) - return order_id.strip() - async def _verified_live_compliance_verdict( self, req: LiveOrderRequest, @@ -1425,10 +960,7 @@ async def submit(self, req: LiveOrderRequest, orderbook: OrderBook, forecast: Fo # Real submission never inherits relaxed evaluate/rehearsal defaults. # Check before authenticated reads, then check again after them so an # expiring authority/risk state cannot win a time-of-check race. - authority = self._mandatory_submit_authority( - req, - forecast=forecast, - ) + authority = self._mandatory_submit_authority(req) if not authority.allow: logger.info( "Live submit blocked by authority", @@ -1468,10 +1000,7 @@ async def submit(self, req: LiveOrderRequest, orderbook: OrderBook, forecast: Fo proof_reference=req.strategy_proof_reference, broker_contacted=False, ) - authority = self._mandatory_submit_authority( - req, - forecast=forecast, - ) + authority = self._mandatory_submit_authority(req) if not authority.allow: return LiveOrderResult( success=False, @@ -1480,57 +1009,6 @@ async def submit(self, req: LiveOrderRequest, orderbook: OrderBook, forecast: Fo broker_contacted=False, ) order = self._build_order(req) - capital_reservation_id: str | None = None - existing_submission = self.exposure.submission_record( - req.proposal_id - ) - if existing_submission is not None: - return LiveOrderResult( - success=False, - error=( - "EXISTING_SUBMISSION_REQUIRES_BROKER_RECONCILIATION" - ), - proof_reference=req.strategy_proof_reference, - broker_contacted=False, - ) - # Reserve the external envelope budget before the local exposure - # reservation. Both are durable and both must succeed. A crash between - # them leaves a conservative external reservation that an identical - # proposal can resume idempotently; it never creates broker authority. - if self.capital_envelope_adapter is not None: - try: - capital = self.capital_envelope_adapter.reserve_request( - req, - current_daily_loss_cents=max( - 0, int(STATE.daily_loss_cents) - ), - current_local_total_exposure_cents=( - self.exposure.total_exposure_cents() - ), - current_local_correlated_exposure_cents=( - self.exposure.correlated_exposure_cents( - req.market_ticker - ) - ), - current_local_open_orders=( - self.exposure.open_order_count() - ), - ) - except Exception as exc: - return LiveOrderResult( - success=False, - error=f"DUMBMONEY_CAPITAL_RESERVATION_FAILED:{type(exc).__name__}", - proof_reference=req.strategy_proof_reference, - broker_contacted=False, - ) - if not capital.allow: - return LiveOrderResult( - success=False, - error=capital.reason, - proof_reference=req.strategy_proof_reference, - broker_contacted=False, - ) - capital_reservation_id = capital.reservation_id # Reserve the full LIMIT notional durably before transport. A timeout # is an unknown broker outcome, not evidence that no order exists. if not self.exposure.reserve_order_submission( @@ -1541,204 +1019,25 @@ async def submit(self, req: LiveOrderRequest, orderbook: OrderBook, forecast: Fo contract_ticker=req.contract_ticker, side=req.side, ): - # The failure may be a concurrent/existing or ambiguously durable - # local reservation. Retain the external reservation until broker - # reconciliation; absence cannot be proven from a false return. - if capital_reservation_id is not None: - logger.warning( - "DumbMoney reservation retained after local failure", - extra={ - "component": "firewall", - "proposal_id": req.proposal_id, - }, - ) return LiveOrderResult( success=False, error="EXPOSURE_RESERVATION_FAILED", proof_reference=req.strategy_proof_reference, broker_contacted=False, ) - from kalshi.client import _CENTRAL_FIREWALL_SUBMIT_CAPABILITY - - mutation_permit: object | None = None - prepare_mutation = ( - getattr(self.client, "prepare_order_mutation") - if inspect.getattr_static( - self.client, - "prepare_order_mutation", - None, - ) - is not None - else None - ) - cancel_mutation = ( - getattr(self.client, "cancel_prepared_order_mutation") - if inspect.getattr_static( - self.client, - "cancel_prepared_order_mutation", - None, - ) - is not None - else None - ) - if callable(prepare_mutation): - try: - # Any queue/limiter wait happens before the last Core - # resolution. The resulting permit authorizes exactly one - # socket attempt and cannot be reused after ambiguity. - mutation_permit = await prepare_mutation( - "POST", - "/portfolio/events/orders", - _capability=_CENTRAL_FIREWALL_SUBMIT_CAPABILITY, - ) - except Exception as exc: - return LiveOrderResult( - success=False, - error=( - "BROKER_MUTATION_PREPARATION_FAILED:" - f"{type(exc).__name__}" - ), - proof_reference=req.strategy_proof_reference, - broker_contacted=False, - ) - - def release_unused_mutation_permit() -> None: - nonlocal mutation_permit - if mutation_permit is None or not callable(cancel_mutation): - return - try: - cancel_mutation( - mutation_permit, - _capability=_CENTRAL_FIREWALL_SUBMIT_CAPABILITY, - ) - except Exception: - logger.exception( - "Unused broker mutation permit release failed", - extra={ - "component": "firewall", - "proposal_id": req.proposal_id, - }, - ) - finally: - mutation_permit = None + try: + from kalshi.client import _CENTRAL_FIREWALL_SUBMIT_CAPABILITY - # Reservation work can cross a short lease or operator-authority - # boundary. Recheck at the last synchronous point before broker I/O. - # If authority disappeared, retain both durable reservations: no - # broker call occurred, but automatically releasing ambiguous - # cross-process state could grant capacity to a concurrent proposal. - authority = self._mandatory_submit_authority( - req, - reservation_held=True, - trusted_orderbook=trusted_orderbook, - forecast=forecast, - ) - if not authority.allow: - release_unused_mutation_permit() - logger.info( - "Live submit blocked after durable reservation", - extra={ - "component": "firewall", - "proposal_id": req.proposal_id, - "rejected_by": authority.rejected_by, - "reason": authority.reason, - }, + resp = await self.client.create_order( + order, + _capability=_CENTRAL_FIREWALL_SUBMIT_CAPABILITY, ) - return LiveOrderResult( - success=False, - error=authority.reason, - proof_reference=req.strategy_proof_reference, - broker_contacted=False, - ) - if self.capital_envelope_adapter is not None: - if capital_reservation_id is None: - release_unused_mutation_permit() - return LiveOrderResult( - success=False, - error="DUMBMONEY_CAPITAL_RESERVATION_MISSING", - proof_reference=req.strategy_proof_reference, - broker_contacted=False, - ) - try: - claimant_nonce = secrets.token_hex(32) - if len(claimant_nonce) != 64: - raise ValueError("dispatch nonce length mismatch") - self.capital_envelope_adapter.claim_broker_dispatch( - req, - reservation_id=capital_reservation_id, - order=order, - claimant_nonce=claimant_nonce, - ) - except Exception as exc: - release_unused_mutation_permit() - logger.error( - "DumbMoney broker dispatch claim failed", - extra={ - "component": "firewall", - "proposal_id": req.proposal_id, - "error_type": type(exc).__name__, - }, - ) - return LiveOrderResult( - success=False, - error=( - "DUMBMONEY_DISPATCH_CLAIM_FAILED:" - f"{type(exc).__name__}" - ), - proof_reference=req.strategy_proof_reference, - broker_contacted=False, - ) - # The command feed and local safety journals are separate durable - # authorities. Recheck after consuming the one-shot dispatch claim - # and immediately before transport. A denial leaves the claim and - # both reservations intact for broker reconciliation; it never - # creates permission to retry the same proposal. - authority = self._mandatory_submit_authority( - req, - reservation_held=True, - trusted_orderbook=trusted_orderbook, - forecast=forecast, - ) - if not authority.allow: - release_unused_mutation_permit() - logger.info( - "Live submit blocked after dispatch claim", - extra={ - "component": "firewall", - "proposal_id": req.proposal_id, - "rejected_by": authority.rejected_by, - "reason": authority.reason, - }, - ) - return LiveOrderResult( - success=False, - error=authority.reason, - proof_reference=req.strategy_proof_reference, - broker_contacted=False, - ) - try: - create_kwargs: dict[str, Any] = { - "_capability": _CENTRAL_FIREWALL_SUBMIT_CAPABILITY, - } - if mutation_permit is not None: - create_kwargs["_mutation_permit"] = mutation_permit - resp = await self.client.create_order(order, **create_kwargs) - mutation_permit = None - if self.capital_envelope_adapter is not None: - order_id = self._validate_v2_create_response( - resp, - request=req, - ) - else: - order_id = ( - resp.get("order", {}).get("order_id") - or resp.get("order_id") - ) + order_id = resp.get("order", {}).get("order_id") or resp.get("order_id") if not order_id: self.exposure.mark_order_outcome_unknown(req.proposal_id) return LiveOrderResult( success=False, - error="AMBIGUOUS_BROKER_OUTCOME:ORDER_ID_MISSING", + error="broker_order_id_missing", proof_reference=req.strategy_proof_reference, broker_contacted=True, ) @@ -1753,9 +1052,6 @@ def release_unused_mutation_permit() -> None: broker_contacted=True, ) except Exception as exc: - # The permit is consumed before the socket call. A transport - # exception, timeout, or HTTP 429 cannot prove non-acceptance. - mutation_permit = None error_type = type(exc).__name__ self.exposure.mark_order_outcome_unknown(req.proposal_id) logger.error( @@ -1764,7 +1060,7 @@ def release_unused_mutation_permit() -> None: ) return LiveOrderResult( success=False, - error=f"AMBIGUOUS_BROKER_OUTCOME:{error_type}", + error=f"broker_submit_failed:{error_type}", proof_reference=req.strategy_proof_reference, broker_contacted=True, ) diff --git a/live_firewall/kalshi_broker_truth.py b/live_firewall/kalshi_broker_truth.py deleted file mode 100644 index c1902d43..00000000 --- a/live_firewall/kalshi_broker_truth.py +++ /dev/null @@ -1,725 +0,0 @@ -"""Credential-owned, read-only Kalshi broker-truth projection for DumbMoney. - -The provider is intentionally narrower than the general Kalshi client. It -uses an injected RSA credential directly, pins the production origin and v2 -path, ignores ambient proxy configuration, performs no retries, and exposes -only a conservative reconciliation snapshot. No order mutation method exists -in this module. -""" - -from __future__ import annotations - -import base64 -import re -import threading -from collections.abc import Callable, Mapping -from dataclasses import dataclass -from datetime import datetime, timedelta, timezone -from decimal import Decimal, InvalidOperation, ROUND_CEILING -from typing import Any - -import httpx -from cryptography.hazmat.primitives import hashes, serialization -from cryptography.hazmat.primitives.asymmetric import padding -from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey - -from kalshi.strict_json import load_strict_json_response -from live_firewall.operational_journal import canonical_json, sha256_json - - -KALSHI_PRODUCTION_ORIGIN = "https://external-api.kalshi.com" -KALSHI_API_PREFIX = "/trade-api/v2" -MAXIMUM_RESPONSE_BYTES = 8 * 1024 * 1024 -MAXIMUM_PAGES = 64 -MAXIMUM_RECORDS = 64_000 -REQUEST_TIMEOUT_SECONDS = 10.0 - -_SHA256_RE = re.compile(r"^[0-9a-f]{64}$") -_KEY_ID_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._:-]{7,255}$") -_IDENTIFIER_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$") -_TICKER_RE = re.compile(r"^[A-Z0-9][A-Z0-9._:-]{0,255}$") -_FIXED_POINT_RE = re.compile( - r"^-?(?:0|[1-9][0-9]{0,18})(?:\.[0-9]{1,6})?$" -) - - -class KalshiBrokerTruthError(RuntimeError): - """The authenticated broker snapshot could not be proven complete.""" - - -@dataclass(frozen=True) -class _BufferedResponse: - content: bytes - - -def _mapping(value: Any, *, field: str) -> Mapping[str, Any]: - if not isinstance(value, Mapping): - raise KalshiBrokerTruthError(f"{field} must be an object") - return value - - -def _list(value: Any, *, field: str) -> list[Any]: - if not isinstance(value, list): - raise KalshiBrokerTruthError(f"{field} must be an array") - return value - - -def _integer( - value: Any, - *, - field: str, - minimum: int = 0, - maximum: int = 2**63 - 1, -) -> int: - if ( - isinstance(value, bool) - or not isinstance(value, int) - or value < minimum - or value > maximum - ): - raise KalshiBrokerTruthError(f"{field} is outside its integer domain") - return value - - -def _identifier(value: Any, *, field: str, ticker: bool = False) -> str: - pattern = _TICKER_RE if ticker else _IDENTIFIER_RE - if not isinstance(value, str) or not pattern.fullmatch(value): - raise KalshiBrokerTruthError(f"{field} is invalid") - return value - - -def _cursor(value: Any, *, field: str) -> str: - if ( - not isinstance(value, str) - or len(value) > 4_096 - or any(ord(character) < 0x20 for character in value) - ): - raise KalshiBrokerTruthError(f"{field} is invalid") - return value - - -def _fixed_point( - value: Any, - *, - field: str, - allow_negative: bool, -) -> Decimal: - if not isinstance(value, str) or not _FIXED_POINT_RE.fullmatch(value): - raise KalshiBrokerTruthError(f"{field} is not a fixed-point string") - try: - parsed = Decimal(value) - except InvalidOperation as exc: - raise KalshiBrokerTruthError(f"{field} is invalid") from exc - if not parsed.is_finite() or (not allow_negative and parsed < 0): - raise KalshiBrokerTruthError(f"{field} is outside its numeric domain") - if parsed.copy_abs() > Decimal("1000000000000000"): - raise KalshiBrokerTruthError(f"{field} exceeds the sealed maximum") - return parsed - - -def _dollars_to_conservative_cents(value: Decimal, *, field: str) -> int: - cents = int( - (value.copy_abs() * Decimal(100)).to_integral_value( - rounding=ROUND_CEILING - ) - ) - return _integer(cents, field=field) - - -def _whole_count(value: Any, *, field: str) -> int: - parsed = _fixed_point(value, field=field, allow_negative=False) - if parsed != parsed.to_integral_value(): - raise KalshiBrokerTruthError( - f"{field} is fractional for a whole-contract DumbMoney order" - ) - return _integer(int(parsed), field=field) - - -def _parse_utc_text(value: Any, *, field: str) -> datetime: - if ( - not isinstance(value, str) - or not value.endswith("Z") - or len(value) > 64 - ): - raise KalshiBrokerTruthError(f"{field} is invalid") - try: - parsed = datetime.fromisoformat(value[:-1] + "+00:00") - except ValueError as exc: - raise KalshiBrokerTruthError(f"{field} is invalid") from exc - if parsed.tzinfo is None or parsed.utcoffset() is None: - raise KalshiBrokerTruthError(f"{field} is timezone-naive") - return parsed.astimezone(timezone.utc) - - -def _format_utc(value: datetime) -> str: - rendered = value.astimezone(timezone.utc).isoformat( - timespec="microseconds" if value.microsecond else "seconds" - ) - return rendered.replace("+00:00", "Z") - - -class KalshiBrokerTruthProvider: - """Build a stable, fully paginated projection of one Kalshi subaccount.""" - - def __init__( - self, - *, - api_key_id: str, - private_key_pem: bytes, - expected_account_hash: str, - subaccount_number: int, - client: httpx.Client | None = None, - clock: Callable[[], datetime] = lambda: datetime.now(timezone.utc), - maximum_pages: int = MAXIMUM_PAGES, - maximum_records: int = MAXIMUM_RECORDS, - ) -> None: - if not isinstance(api_key_id, str) or not _KEY_ID_RE.fullmatch( - api_key_id - ): - raise KalshiBrokerTruthError("Kalshi API key id is invalid") - if not isinstance(private_key_pem, bytes): - raise KalshiBrokerTruthError("Kalshi private key must be bytes") - try: - private_key = serialization.load_pem_private_key( - private_key_pem, - password=None, - ) - except (TypeError, ValueError) as exc: - raise KalshiBrokerTruthError( - "Kalshi private key is invalid" - ) from exc - if ( - not isinstance(private_key, RSAPrivateKey) - or private_key.key_size < 2_048 - ): - raise KalshiBrokerTruthError( - "Kalshi private key must be RSA with at least 2048 bits" - ) - if ( - not isinstance(expected_account_hash, str) - or not _SHA256_RE.fullmatch(expected_account_hash) - ): - raise KalshiBrokerTruthError("expected account hash is invalid") - if ( - isinstance(subaccount_number, bool) - or not isinstance(subaccount_number, int) - or subaccount_number != 0 - ): - raise KalshiBrokerTruthError( - "only the sealed primary Kalshi subaccount is supported" - ) - binding_hash = sha256_json( - { - "schema": "dummy.kalshi-account-binding.v1", - "venue": "dummy_kalshi", - "api_key_id": api_key_id, - "subaccount_number": subaccount_number, - } - ) - if binding_hash != expected_account_hash: - raise KalshiBrokerTruthError( - "Kalshi key and subaccount do not match the account pin" - ) - if ( - isinstance(maximum_pages, bool) - or not isinstance(maximum_pages, int) - or not 1 <= maximum_pages <= MAXIMUM_PAGES - ): - raise KalshiBrokerTruthError("maximum_pages is invalid") - if ( - isinstance(maximum_records, bool) - or not isinstance(maximum_records, int) - or not 1 <= maximum_records <= MAXIMUM_RECORDS - ): - raise KalshiBrokerTruthError("maximum_records is invalid") - - self._api_key_id = api_key_id - self._private_key = private_key - self._expected_account_hash = expected_account_hash - self._subaccount_number = subaccount_number - self._clock = clock - self._maximum_pages = maximum_pages - self._maximum_records = maximum_records - self._lock = threading.Lock() - self._client = client or httpx.Client( - base_url=f"{KALSHI_PRODUCTION_ORIGIN}{KALSHI_API_PREFIX}/", - timeout=httpx.Timeout(REQUEST_TIMEOUT_SECONDS), - follow_redirects=False, - trust_env=False, - limits=httpx.Limits( - max_connections=1, - max_keepalive_connections=1, - ), - ) - - def _now(self) -> datetime: - value = self._clock() - if value.tzinfo is None or value.utcoffset() is None: - raise KalshiBrokerTruthError( - "broker-truth clock must be timezone-aware" - ) - return value.astimezone(timezone.utc) - - def _headers(self, endpoint_path: str) -> dict[str, str]: - timestamp = str(int(self._now().timestamp() * 1_000)) - signed_path = f"{KALSHI_API_PREFIX}/{endpoint_path.lstrip('/')}" - message = f"{timestamp}GET{signed_path}".encode("utf-8") - signature = self._private_key.sign( - message, - padding.PSS( - mgf=padding.MGF1(hashes.SHA256()), - salt_length=padding.PSS.DIGEST_LENGTH, - ), - hashes.SHA256(), - ) - return { - "Accept": "application/json", - "KALSHI-ACCESS-KEY": self._api_key_id, - "KALSHI-ACCESS-SIGNATURE": base64.b64encode(signature).decode( - "ascii" - ), - "KALSHI-ACCESS-TIMESTAMP": timestamp, - } - - def _request( - self, - endpoint_path: str, - *, - params: Mapping[str, Any], - ) -> Mapping[str, Any]: - if endpoint_path not in { - "historical/fills", - "historical/orders", - "portfolio/balance", - "portfolio/fills", - "portfolio/positions", - "portfolio/orders", - "portfolio/settlements", - }: - raise KalshiBrokerTruthError("broker-truth endpoint is not allowed") - try: - with self._client.stream( - "GET", - endpoint_path, - params=dict(params), - headers=self._headers(endpoint_path), - ) as response: - response_url = response.request.url - expected_path = ( - f"{KALSHI_API_PREFIX}/{endpoint_path.lstrip('/')}" - ) - if ( - response_url.scheme != "https" - or response_url.host != "external-api.kalshi.com" - or response_url.port not in {None, 443} - or response_url.path != expected_path - ): - raise KalshiBrokerTruthError( - "Kalshi response origin or path is not sealed" - ) - length_header = response.headers.get("content-length") - if length_header is not None: - try: - content_length = int(length_header) - except ValueError as exc: - raise KalshiBrokerTruthError( - "Kalshi Content-Length is invalid" - ) from exc - if ( - content_length < 0 - or content_length > MAXIMUM_RESPONSE_BYTES - ): - raise KalshiBrokerTruthError( - "Kalshi response exceeds the byte limit" - ) - body = bytearray() - for chunk in response.iter_bytes(): - body.extend(chunk) - if len(body) > MAXIMUM_RESPONSE_BYTES: - raise KalshiBrokerTruthError( - "Kalshi response exceeds the byte limit" - ) - if response.status_code != 200: - raise KalshiBrokerTruthError( - "Kalshi read failed with " - f"HTTP status {response.status_code}" - ) - except KalshiBrokerTruthError: - raise - except (httpx.HTTPError, OSError) as exc: - raise KalshiBrokerTruthError( - "Kalshi read transport failed" - ) from exc - try: - payload = load_strict_json_response( - _BufferedResponse(bytes(body)), - maximum_bytes=MAXIMUM_RESPONSE_BYTES, - ) - except (TypeError, ValueError) as exc: - raise KalshiBrokerTruthError( - "Kalshi read response is not strict bounded JSON" - ) from exc - return _mapping(payload, field=f"Kalshi {endpoint_path} response") - - def _balance(self) -> dict[str, int | str]: - payload = self._request( - "portfolio/balance", - params={"subaccount": self._subaccount_number}, - ) - balance = _integer(payload.get("balance"), field="balance") - portfolio_value = _integer( - payload.get("portfolio_value"), - field="portfolio_value", - ) - updated_ts = _integer( - payload.get("updated_ts"), - field="updated_ts", - ) - balance_dollars = _fixed_point( - payload.get("balance_dollars"), - field="balance_dollars", - allow_negative=False, - ) - if balance_dollars * Decimal(100) != Decimal(balance): - raise KalshiBrokerTruthError( - "balance cents and fixed-point dollars disagree" - ) - return { - "balance_cents": balance, - "balance_dollars": str(balance_dollars), - "portfolio_value_cents": portfolio_value, - "updated_ts": updated_ts, - } - - def _positions(self) -> dict[str, list[dict[str, Any]]]: - market_positions: list[dict[str, Any]] = [] - event_positions: list[dict[str, Any]] = [] - seen_market: set[str] = set() - seen_event: set[str] = set() - seen_cursors: set[str] = set() - cursor = "" - - for _page in range(self._maximum_pages): - params: dict[str, Any] = { - "limit": 1_000, - "count_filter": "position", - "subaccount": self._subaccount_number, - } - if cursor: - params["cursor"] = cursor - payload = self._request("portfolio/positions", params=params) - markets = _list( - payload.get("market_positions"), - field="market_positions", - ) - events = _list( - payload.get("event_positions"), - field="event_positions", - ) - for index, raw in enumerate(markets): - item = _mapping( - raw, - field=f"market_positions[{index}]", - ) - ticker = _identifier( - item.get("ticker"), - field="market position ticker", - ticker=True, - ) - if ticker in seen_market: - raise KalshiBrokerTruthError( - "market position ticker is duplicated" - ) - seen_market.add(ticker) - position = _fixed_point( - item.get("position_fp"), - field=f"{ticker}.position_fp", - allow_negative=True, - ) - if position == 0: - raise KalshiBrokerTruthError( - "position-filtered response contains a zero position" - ) - exposure = _fixed_point( - item.get("market_exposure_dollars"), - field=f"{ticker}.market_exposure_dollars", - allow_negative=True, - ) - updated = item.get("last_updated_ts") - if ( - not isinstance(updated, str) - or not updated.endswith("Z") - or len(updated) > 64 - ): - raise KalshiBrokerTruthError( - "market position timestamp is invalid" - ) - try: - parsed_updated = datetime.fromisoformat( - updated[:-1] + "+00:00" - ) - except ValueError as exc: - raise KalshiBrokerTruthError( - "market position timestamp is invalid" - ) from exc - if ( - parsed_updated.tzinfo is None - or parsed_updated.utcoffset() is None - ): - raise KalshiBrokerTruthError( - "market position timestamp is naive" - ) - if parsed_updated > self._now() + timedelta(seconds=5): - raise KalshiBrokerTruthError( - "market position timestamp is in the future" - ) - market_positions.append( - { - "ticker": ticker, - "position_fp": str(position), - "market_exposure_cents": ( - _dollars_to_conservative_cents( - exposure, - field=f"{ticker}.market_exposure_cents", - ) - ), - "last_updated_ts": _format_utc(parsed_updated), - } - ) - for index, raw in enumerate(events): - item = _mapping( - raw, - field=f"event_positions[{index}]", - ) - event_ticker = _identifier( - item.get("event_ticker"), - field="event position ticker", - ticker=True, - ) - if event_ticker in seen_event: - raise KalshiBrokerTruthError( - "event position ticker is duplicated" - ) - seen_event.add(event_ticker) - exposure = _fixed_point( - item.get("event_exposure_dollars"), - field=f"{event_ticker}.event_exposure_dollars", - allow_negative=True, - ) - event_positions.append( - { - "event_ticker": event_ticker, - "event_exposure_cents": ( - _dollars_to_conservative_cents( - exposure, - field=( - f"{event_ticker}.event_exposure_cents" - ), - ) - ), - } - ) - if ( - len(market_positions) + len(event_positions) - > self._maximum_records - ): - raise KalshiBrokerTruthError( - "position snapshot exceeds the record limit" - ) - next_cursor = _cursor( - payload.get("cursor"), - field="positions cursor", - ) - if not next_cursor: - market_positions.sort(key=lambda item: item["ticker"]) - event_positions.sort(key=lambda item: item["event_ticker"]) - return { - "market_positions": market_positions, - "event_positions": event_positions, - } - if next_cursor == cursor or next_cursor in seen_cursors: - raise KalshiBrokerTruthError( - "positions cursor repeated" - ) - seen_cursors.add(next_cursor) - cursor = next_cursor - raise KalshiBrokerTruthError("positions pagination is incomplete") - - def _orders(self) -> list[dict[str, Any]]: - orders: list[dict[str, Any]] = [] - seen_orders: set[str] = set() - seen_cursors: set[str] = set() - cursor = "" - - for _page in range(self._maximum_pages): - params: dict[str, Any] = { - "status": "resting", - "limit": 1_000, - "subaccount": self._subaccount_number, - } - if cursor: - params["cursor"] = cursor - payload = self._request("portfolio/orders", params=params) - page_orders = _list(payload.get("orders"), field="orders") - for index, raw in enumerate(page_orders): - item = _mapping(raw, field=f"orders[{index}]") - order_id = _identifier( - item.get("order_id"), - field="order_id", - ) - if order_id in seen_orders: - raise KalshiBrokerTruthError("order_id is duplicated") - seen_orders.add(order_id) - ticker = _identifier( - item.get("ticker"), - field=f"{order_id}.ticker", - ticker=True, - ) - subaccount = _integer( - item.get("subaccount_number"), - field=f"{order_id}.subaccount_number", - maximum=63, - ) - if subaccount != self._subaccount_number: - raise KalshiBrokerTruthError( - "order belongs to a different subaccount" - ) - remaining = _fixed_point( - item.get("remaining_count_fp"), - field=f"{order_id}.remaining_count_fp", - allow_negative=False, - ) - if remaining <= 0: - raise KalshiBrokerTruthError( - "resting order has no remaining count" - ) - yes_price = _fixed_point( - item.get("yes_price_dollars"), - field=f"{order_id}.yes_price_dollars", - allow_negative=False, - ) - no_price = _fixed_point( - item.get("no_price_dollars"), - field=f"{order_id}.no_price_dollars", - allow_negative=False, - ) - if ( - yes_price > 1 - or no_price > 1 - or yes_price + no_price != 1 - ): - raise KalshiBrokerTruthError( - "order price pair is inconsistent" - ) - orders.append( - { - "order_id": order_id, - "ticker": ticker, - "subaccount_number": subaccount, - "remaining_count_fp": str(remaining), - "yes_price_dollars": str(yes_price), - "no_price_dollars": str(no_price), - } - ) - if len(orders) > self._maximum_records: - raise KalshiBrokerTruthError( - "order snapshot exceeds the record limit" - ) - next_cursor = _cursor( - payload.get("cursor"), - field="orders cursor", - ) - if not next_cursor: - orders.sort(key=lambda item: item["order_id"]) - return orders - if next_cursor == cursor or next_cursor in seen_cursors: - raise KalshiBrokerTruthError("orders cursor repeated") - seen_cursors.add(next_cursor) - cursor = next_cursor - raise KalshiBrokerTruthError("orders pagination is incomplete") - - def _stable_state(self) -> dict[str, Any]: - return { - "positions": self._positions(), - "resting_orders": self._orders(), - } - - def snapshot(self) -> Mapping[str, Any]: - """Return one stable account-scoped truth projection or fail closed.""" - if not self._lock.acquire(blocking=False): - raise KalshiBrokerTruthError( - "a broker-truth snapshot is already in progress" - ) - try: - balance = self._balance() - first_state = self._stable_state() - second_state = self._stable_state() - if canonical_json(first_state) != canonical_json(second_state): - raise KalshiBrokerTruthError( - "Kalshi positions or orders changed during reconciliation" - ) - observed_at = self._now() - market_positions = first_state["positions"]["market_positions"] - event_positions = first_state["positions"]["event_positions"] - resting_orders = first_state["resting_orders"] - if event_positions and not market_positions: - raise KalshiBrokerTruthError( - "event exposure exists without a market position" - ) - market_exposure = { - item["ticker"]: item["market_exposure_cents"] - for item in market_positions - } - correlated_exposure = { - item["event_ticker"]: item["event_exposure_cents"] - for item in event_positions - } - market_total = sum(market_exposure.values()) - correlated_total = sum(correlated_exposure.values()) - total_exposure = max(market_total, correlated_total) - if market_positions and not correlated_exposure: - correlated_exposure = { - "ACCOUNT_WIDE_UNGROUPED": total_exposure - } - flat = ( - not market_positions - and not resting_orders - and total_exposure == 0 - ) - digest_payload = { - "schema": "dummy.kalshi-broker-raw-snapshot.v1", - "venue": "dummy_kalshi", - "account_hash": self._expected_account_hash, - "subaccount_number": self._subaccount_number, - "observed_at": _format_utc(observed_at), - "balance": balance, - "state": first_state, - } - return { - "schema": "dummy.kalshi-broker-truth.v1", - "venue": "dummy_kalshi", - "account_hash": self._expected_account_hash, - "subaccount_number": self._subaccount_number, - "observed_at": digest_payload["observed_at"], - "broker_snapshot_sha256": sha256_json(digest_payload), - "flat_book_observed": flat, - "total_exposure_cents": total_exposure, - "open_order_count": len(resting_orders), - "market_exposure_cents": market_exposure, - "correlated_exposure_cents": correlated_exposure, - "unresolved_open_orders": len(resting_orders), - "unresolved_positions": len(market_positions), - } - finally: - self._lock.release() - - def close(self) -> None: - self._client.close() - - -__all__ = [ - "KALSHI_API_PREFIX", - "KALSHI_PRODUCTION_ORIGIN", - "KalshiBrokerTruthError", - "KalshiBrokerTruthProvider", -] diff --git a/live_firewall/kalshi_reconciliation.py b/live_firewall/kalshi_reconciliation.py deleted file mode 100644 index 2c1113ad..00000000 --- a/live_firewall/kalshi_reconciliation.py +++ /dev/null @@ -1,891 +0,0 @@ -"""Read-only, signed Kalshi reconciliation witnesses for DumbMoney. - -The reader intentionally queries both current and historical portfolio tiers. -Kalshi partitions completed orders and fills at moving cutoffs, so consulting -only the live portfolio endpoints cannot prove absence or completeness after a -restart. Every collection is fully paginated, normalized, and read twice -before the local venue identity signs the resulting witness. -""" - -from __future__ import annotations - -from collections.abc import Mapping -from datetime import timedelta -from decimal import Decimal, ROUND_CEILING -from typing import Any - -from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey - -from live_firewall.dumbmoney_broker_witness import ( - SETTLEMENT_WITNESS_SCHEMA, - TERMINAL_WITNESS_SCHEMA, - sign_broker_witness, -) -from live_firewall.kalshi_broker_truth import ( - KalshiBrokerTruthError, - KalshiBrokerTruthProvider, - _cursor, - _dollars_to_conservative_cents, - _fixed_point, - _format_utc, - _identifier, - _integer, - _list, - _mapping, - _parse_utc_text, - _whole_count, -) -from live_firewall.operational_journal import canonical_json, sha256_json - - -class KalshiReconciliationReader: - """Produce signed terminal and settlement facts without mutation methods.""" - - def __init__( - self, - *, - broker_truth: KalshiBrokerTruthProvider, - witness_signing_private_key: Ed25519PrivateKey, - ) -> None: - self._broker_truth = broker_truth - self._witness_signing_private_key = witness_signing_private_key - - def _paginated_rows( - self, - endpoint_path: str, - *, - collection: str, - base_params: Mapping[str, Any], - ) -> list[Mapping[str, Any]]: - rows: list[Mapping[str, Any]] = [] - seen_cursors: set[str] = set() - cursor = "" - for _page in range(self._broker_truth._maximum_pages): - params = {"limit": 1_000, **dict(base_params)} - if cursor: - params["cursor"] = cursor - payload = self._broker_truth._request( - endpoint_path, - params=params, - ) - page = _list(payload.get(collection), field=collection) - for index, raw in enumerate(page): - rows.append( - _mapping(raw, field=f"{collection}[{index}]") - ) - if len(rows) > self._broker_truth._maximum_records: - raise KalshiBrokerTruthError( - f"{collection} snapshot exceeds the record limit" - ) - next_cursor = _cursor( - payload.get("cursor"), - field=f"{collection} cursor", - ) - if not next_cursor: - return rows - if next_cursor == cursor or next_cursor in seen_cursors: - raise KalshiBrokerTruthError( - f"{collection} cursor repeated" - ) - seen_cursors.add(next_cursor) - cursor = next_cursor - raise KalshiBrokerTruthError( - f"{collection} pagination is incomplete" - ) - - def _normalized_order( - self, - raw: Mapping[str, Any], - *, - source_tier: str, - ) -> dict[str, Any]: - order_id = _identifier(raw.get("order_id"), field="order_id") - client_order_id = _identifier( - raw.get("client_order_id"), - field=f"{order_id}.client_order_id", - ) - ticker = _identifier( - raw.get("ticker"), - field=f"{order_id}.ticker", - ticker=True, - ) - status = raw.get("status") - if status not in {"resting", "canceled", "executed"}: - raise KalshiBrokerTruthError("order status is unsupported") - if raw.get("action") != "buy": - raise KalshiBrokerTruthError( - "DumbMoney reconciliation observed a non-buy order" - ) - outcome_side = raw.get("outcome_side") - book_side = raw.get("book_side") - if outcome_side not in {"yes", "no"}: - raise KalshiBrokerTruthError("order outcome_side is invalid") - if book_side != ("bid" if outcome_side == "yes" else "ask"): - raise KalshiBrokerTruthError( - "order direction fields are inconsistent" - ) - subaccount = _integer( - raw.get("subaccount_number"), - field=f"{order_id}.subaccount_number", - maximum=63, - ) - initial_count = _whole_count( - raw.get("initial_count_fp"), - field=f"{order_id}.initial_count_fp", - ) - fill_count = _whole_count( - raw.get("fill_count_fp"), - field=f"{order_id}.fill_count_fp", - ) - remaining_count = _whole_count( - raw.get("remaining_count_fp"), - field=f"{order_id}.remaining_count_fp", - ) - if ( - initial_count < 1 - or fill_count > initial_count - or remaining_count > initial_count - fill_count - ): - raise KalshiBrokerTruthError("order counts are inconsistent") - yes_price = _fixed_point( - raw.get("yes_price_dollars"), - field=f"{order_id}.yes_price_dollars", - allow_negative=False, - ) - no_price = _fixed_point( - raw.get("no_price_dollars"), - field=f"{order_id}.no_price_dollars", - allow_negative=False, - ) - if ( - yes_price > 1 - or no_price > 1 - or yes_price + no_price != 1 - ): - raise KalshiBrokerTruthError( - "order price pair is inconsistent" - ) - taker_cost = _fixed_point( - raw.get("taker_fill_cost_dollars"), - field=f"{order_id}.taker_fill_cost_dollars", - allow_negative=False, - ) - maker_cost = _fixed_point( - raw.get("maker_fill_cost_dollars"), - field=f"{order_id}.maker_fill_cost_dollars", - allow_negative=False, - ) - taker_fees = _fixed_point( - raw.get("taker_fees_dollars"), - field=f"{order_id}.taker_fees_dollars", - allow_negative=False, - ) - maker_fees = _fixed_point( - raw.get("maker_fees_dollars"), - field=f"{order_id}.maker_fees_dollars", - allow_negative=False, - ) - created = _parse_utc_text( - raw.get("created_time"), - field=f"{order_id}.created_time", - ) - updated = _parse_utc_text( - raw.get("last_update_time"), - field=f"{order_id}.last_update_time", - ) - if ( - updated < created - or updated - > self._broker_truth._now() + timedelta(seconds=5) - ): - raise KalshiBrokerTruthError( - "order timestamps are inconsistent" - ) - return { - "order_id": order_id, - "client_order_id": client_order_id, - "ticker": ticker, - "status": status, - "outcome_side": outcome_side, - "book_side": book_side, - "subaccount_number": subaccount, - "initial_count": initial_count, - "fill_count": fill_count, - "remaining_count": remaining_count, - "yes_price_dollars": str(yes_price), - "no_price_dollars": str(no_price), - "fill_cost_dollars": str(taker_cost + maker_cost), - "fee_dollars": str(taker_fees + maker_fees), - "created_time": _format_utc(created), - "last_update_time": _format_utc(updated), - "source_tier": source_tier, - } - - @staticmethod - def _merge_tiered_row( - rows: dict[str, dict[str, Any]], - normalized: dict[str, Any], - *, - identity_field: str, - conflict_message: str, - ) -> None: - identity = str(normalized[identity_field]) - prior = rows.get(identity) - if prior is None: - rows[identity] = normalized - return - comparable_prior = { - key: value - for key, value in prior.items() - if key != "source_tier" - } - comparable_current = { - key: value - for key, value in normalized.items() - if key != "source_tier" - } - if comparable_prior != comparable_current: - raise KalshiBrokerTruthError(conflict_message) - prior["source_tier"] = "both" - - def _orders(self, ticker: str) -> list[dict[str, Any]]: - tiers = ( - ( - "portfolio", - "portfolio/orders", - { - "ticker": ticker, - "subaccount": self._broker_truth._subaccount_number, - }, - ), - ( - "historical", - "historical/orders", - {"ticker": ticker}, - ), - ) - by_id: dict[str, dict[str, Any]] = {} - for source_tier, endpoint, params in tiers: - for raw in self._paginated_rows( - endpoint, - collection="orders", - base_params=params, - ): - normalized = self._normalized_order( - raw, - source_tier=source_tier, - ) - if ( - normalized["subaccount_number"] - != self._broker_truth._subaccount_number - ): - if source_tier == "portfolio": - raise KalshiBrokerTruthError( - "live order belongs to a different subaccount" - ) - continue - self._merge_tiered_row( - by_id, - normalized, - identity_field="order_id", - conflict_message=( - "live and historical order rows conflict" - ), - ) - return sorted(by_id.values(), key=lambda item: item["order_id"]) - - def _normalized_fill( - self, - raw: Mapping[str, Any], - *, - source_tier: str, - ) -> dict[str, Any]: - fill_id = _identifier(raw.get("fill_id"), field="fill_id") - order_id = _identifier( - raw.get("order_id"), - field=f"{fill_id}.order_id", - ) - ticker = _identifier( - raw.get("ticker"), - field=f"{fill_id}.ticker", - ticker=True, - ) - market_ticker = _identifier( - raw.get("market_ticker"), - field=f"{fill_id}.market_ticker", - ticker=True, - ) - if raw.get("action") != "buy": - raise KalshiBrokerTruthError( - "DumbMoney reconciliation observed a non-buy fill" - ) - outcome_side = raw.get("outcome_side") - book_side = raw.get("book_side") - if outcome_side not in {"yes", "no"}: - raise KalshiBrokerTruthError("fill outcome_side is invalid") - if book_side != ("bid" if outcome_side == "yes" else "ask"): - raise KalshiBrokerTruthError( - "fill direction fields are inconsistent" - ) - subaccount = _integer( - raw.get("subaccount_number"), - field=f"{fill_id}.subaccount_number", - maximum=63, - ) - count = _whole_count( - raw.get("count_fp"), - field=f"{fill_id}.count_fp", - ) - if count < 1: - raise KalshiBrokerTruthError("fill count must be positive") - yes_price = _fixed_point( - raw.get("yes_price_dollars"), - field=f"{fill_id}.yes_price_dollars", - allow_negative=False, - ) - no_price = _fixed_point( - raw.get("no_price_dollars"), - field=f"{fill_id}.no_price_dollars", - allow_negative=False, - ) - if ( - yes_price > 1 - or no_price > 1 - or yes_price + no_price != 1 - ): - raise KalshiBrokerTruthError("fill price pair is inconsistent") - fee = _fixed_point( - raw.get("fee_cost"), - field=f"{fill_id}.fee_cost", - allow_negative=False, - ) - created = _parse_utc_text( - raw.get("created_time"), - field=f"{fill_id}.created_time", - ) - if ( - created - > self._broker_truth._now() + timedelta(seconds=5) - ): - raise KalshiBrokerTruthError( - "fill timestamp is in the future" - ) - price = yes_price if outcome_side == "yes" else no_price - return { - "fill_id": fill_id, - "order_id": order_id, - "ticker": ticker, - "market_ticker": market_ticker, - "outcome_side": outcome_side, - "book_side": book_side, - "subaccount_number": subaccount, - "count": count, - "price_dollars": str(price), - "cost_dollars": str(price * count), - "fee_dollars": str(fee), - "created_time": _format_utc(created), - "source_tier": source_tier, - } - - def _fills( - self, - *, - order_id: str, - ticker: str, - ) -> list[dict[str, Any]]: - tiers = ( - ( - "portfolio", - "portfolio/fills", - { - "order_id": order_id, - "subaccount": self._broker_truth._subaccount_number, - }, - ), - ( - "historical", - "historical/fills", - {"ticker": ticker}, - ), - ) - by_id: dict[str, dict[str, Any]] = {} - for source_tier, endpoint, params in tiers: - for raw in self._paginated_rows( - endpoint, - collection="fills", - base_params=params, - ): - normalized = self._normalized_fill( - raw, - source_tier=source_tier, - ) - if ( - normalized["subaccount_number"] - != self._broker_truth._subaccount_number - ): - if source_tier == "portfolio": - raise KalshiBrokerTruthError( - "live fill belongs to a different subaccount" - ) - continue - if normalized["order_id"] != order_id: - if source_tier == "portfolio": - raise KalshiBrokerTruthError( - "live fill query returned another order" - ) - continue - self._merge_tiered_row( - by_id, - normalized, - identity_field="fill_id", - conflict_message=( - "live and historical fill rows conflict" - ), - ) - return sorted(by_id.values(), key=lambda item: item["fill_id"]) - - def _terminal_projection( - self, - reservation: Mapping[str, Any], - ) -> dict[str, Any]: - proposal_id = _identifier( - reservation.get("proposal_id"), - field="reservation.proposal_id", - ) - ticker = _identifier( - reservation.get("contract_ticker"), - field="reservation.contract_ticker", - ticker=True, - ) - side = reservation.get("side") - if side not in {"yes", "no"}: - raise KalshiBrokerTruthError("reservation side is invalid") - size = _integer( - reservation.get("size"), - field="reservation.size", - minimum=1, - ) - price_cents = _integer( - reservation.get("price_cents"), - field="reservation.price_cents", - minimum=1, - maximum=99, - ) - orders = [ - order - for order in self._orders(ticker) - if order["client_order_id"] == proposal_id - ] - if len(orders) > 1: - raise KalshiBrokerTruthError( - "client_order_id resolves to multiple broker orders" - ) - if not orders: - return { - "state": "NOT_FOUND", - "proposal_id": proposal_id, - "ticker": ticker, - } - order = orders[0] - if ( - order["ticker"] != ticker - or order["outcome_side"] != side - or order["initial_count"] != size - or ( - Decimal( - str(order[f"{side}_price_dollars"]) - ) - * Decimal(100) - != Decimal(price_cents) - ) - ): - raise KalshiBrokerTruthError( - "broker order differs from the capital reservation" - ) - if order["status"] == "resting": - if order["remaining_count"] <= 0: - raise KalshiBrokerTruthError( - "resting order has no remaining count" - ) - return {"state": "RESTING", "order": order} - if order["remaining_count"] != 0: - raise KalshiBrokerTruthError( - "terminal order retains a remaining count" - ) - if ( - order["status"] == "executed" - and order["fill_count"] != size - ): - raise KalshiBrokerTruthError( - "executed order lacks a complete fill" - ) - fills = self._fills( - order_id=order["order_id"], - ticker=ticker, - ) - fill_count = sum(int(item["count"]) for item in fills) - fill_cost = sum( - ( - Decimal(str(item["cost_dollars"])) - for item in fills - ), - Decimal(0), - ) - fee_cost = sum( - ( - Decimal(str(item["fee_dollars"])) - for item in fills - ), - Decimal(0), - ) - if ( - fill_count != order["fill_count"] - or fill_cost != Decimal(str(order["fill_cost_dollars"])) - or fee_cost != Decimal(str(order["fee_dollars"])) - or any(item["ticker"] != ticker for item in fills) - or any(item["outcome_side"] != side for item in fills) - ): - raise KalshiBrokerTruthError( - "order and fill projections disagree" - ) - return { - "state": "TERMINAL", - "order": order, - "fills": fills, - "fill_count": fill_count, - "fill_cost_dollars": str(fill_cost), - "fee_dollars": str(fee_cost), - } - - def terminal_reconciliation_witness( - self, - reservation: Mapping[str, Any], - ) -> Mapping[str, Any] | None: - """Return a signed terminal witness, or retain unresolved authority.""" - first = self._terminal_projection(reservation) - second = self._terminal_projection(reservation) - if canonical_json(first) != canonical_json(second): - raise KalshiBrokerTruthError( - "order or fill state changed during reconciliation" - ) - if first["state"] != "TERMINAL": - return None - observed = self._broker_truth._now() - order = first["order"] - fill_count = int(first["fill_count"]) - fill_cost = Decimal(str(first["fill_cost_dollars"])) - fee = Decimal(str(first["fee_dollars"])) - average_price_cents = ( - int( - ( - fill_cost - * Decimal(100) - / Decimal(fill_count) - ).to_integral_value(rounding=ROUND_CEILING) - ) - if fill_count - else None - ) - projection_digest = sha256_json( - { - "schema": "dummy.kalshi-terminal-projection.v1", - "projection": first, - } - ) - invariant = { - "venue": "dummy_kalshi", - "account_hash": self._broker_truth._expected_account_hash, - "subaccount_number": ( - self._broker_truth._subaccount_number - ), - "reservation_id": reservation.get("reservation_id"), - "proposal_id": reservation.get("proposal_id"), - "order": first["order"], - "fills": first["fills"], - } - body = { - "schema": TERMINAL_WITNESS_SCHEMA, - "witness_id": sha256_json(invariant), - "venue": "dummy_kalshi", - "account_hash": self._broker_truth._expected_account_hash, - "subaccount_number": ( - self._broker_truth._subaccount_number - ), - "reservation_id": _identifier( - reservation.get("reservation_id"), - field="reservation.reservation_id", - ), - "proposal_id": order["client_order_id"], - "order_id": order["order_id"], - "market_ticker": _identifier( - reservation.get("market_ticker"), - field="reservation.market_ticker", - ticker=True, - ), - "contract_ticker": order["ticker"], - "side": order["outcome_side"], - "terminal_status": order["status"], - "initial_count": order["initial_count"], - "fill_count": fill_count, - "remaining_count": order["remaining_count"], - "fill_cost_cents": _dollars_to_conservative_cents( - fill_cost, - field="fill_cost_cents", - ), - "fee_cents": _dollars_to_conservative_cents( - fee, - field="fee_cents", - ), - "average_fill_price_cents": average_price_cents, - "fill_ids": [item["fill_id"] for item in first["fills"]], - "observed_at": _format_utc(observed), - "broker_projection_sha256": projection_digest, - } - return sign_broker_witness( - body, - private_key=self._witness_signing_private_key, - observed_at=observed, - correlation_id=order["client_order_id"], - ) - - def _settlements(self, ticker: str) -> list[dict[str, Any]]: - rows = self._paginated_rows( - "portfolio/settlements", - collection="settlements", - base_params={ - "ticker": ticker, - "subaccount": self._broker_truth._subaccount_number, - }, - ) - settlements: list[dict[str, Any]] = [] - seen: set[str] = set() - for raw in rows: - row_ticker = _identifier( - raw.get("ticker"), - field="settlement.ticker", - ticker=True, - ) - if row_ticker in seen: - raise KalshiBrokerTruthError( - "settlement ticker is duplicated" - ) - seen.add(row_ticker) - result = raw.get("market_result") - if result not in {"yes", "no"}: - raise KalshiBrokerTruthError( - "settlement result is invalid" - ) - settled = _parse_utc_text( - raw.get("settled_time"), - field=f"{row_ticker}.settled_time", - ) - if ( - settled - > self._broker_truth._now() + timedelta(seconds=5) - ): - raise KalshiBrokerTruthError( - "settlement timestamp is in the future" - ) - yes_count = _fixed_point( - raw.get("yes_count_fp"), - field=f"{row_ticker}.yes_count_fp", - allow_negative=False, - ) - no_count = _fixed_point( - raw.get("no_count_fp"), - field=f"{row_ticker}.no_count_fp", - allow_negative=False, - ) - yes_cost = _fixed_point( - raw.get("yes_total_cost_dollars"), - field=f"{row_ticker}.yes_total_cost_dollars", - allow_negative=False, - ) - no_cost = _fixed_point( - raw.get("no_total_cost_dollars"), - field=f"{row_ticker}.no_total_cost_dollars", - allow_negative=False, - ) - fee = _fixed_point( - raw.get("fee_cost"), - field=f"{row_ticker}.fee_cost", - allow_negative=False, - ) - revenue = _integer( - raw.get("revenue"), - field=f"{row_ticker}.revenue", - ) - settlements.append( - { - "ticker": row_ticker, - "event_ticker": _identifier( - raw.get("event_ticker"), - field=f"{row_ticker}.event_ticker", - ticker=True, - ), - "market_result": result, - "yes_count_fp": str(yes_count), - "no_count_fp": str(no_count), - "yes_total_cost_dollars": str(yes_cost), - "no_total_cost_dollars": str(no_cost), - "fee_cost_dollars": str(fee), - "revenue_cents": revenue, - "settled_time": _format_utc(settled), - } - ) - return sorted(settlements, key=lambda item: item["ticker"]) - - def _settlement_projection( - self, - position_exposure: Mapping[str, Any], - ) -> dict[str, Any]: - ticker = _identifier( - position_exposure.get("contract_ticker"), - field="position_exposure.contract_ticker", - ticker=True, - ) - positions = self._broker_truth._positions() - market_positions = [ - item - for item in positions["market_positions"] - if item["ticker"] == ticker - ] - settlements = [ - item - for item in self._settlements(ticker) - if item["ticker"] == ticker - ] - if market_positions: - return { - "state": "POSITION_OPEN", - "positions": market_positions, - "settlements": settlements, - } - if len(settlements) > 1: - raise KalshiBrokerTruthError( - "multiple settlement rows exist for one market" - ) - if not settlements: - return { - "state": "POSITION_ABSENT_UNSETTLED", - "positions": [], - "settlements": [], - } - side = position_exposure.get("side") - if side not in {"yes", "no"}: - raise KalshiBrokerTruthError( - "position exposure side is invalid" - ) - settlement = settlements[0] - position_observed = _parse_utc_text( - position_exposure.get("observed_at"), - field="position_exposure.observed_at", - ) - settlement_observed = _parse_utc_text( - settlement["settled_time"], - field="settlement.settled_time", - ) - if settlement_observed < position_observed: - raise KalshiBrokerTruthError( - "settlement predates the filled position exposure" - ) - settled_count = Decimal( - str(settlement[f"{side}_count_fp"]) - ) - fill_count = _integer( - position_exposure.get("fill_count"), - field="position_exposure.fill_count", - minimum=1, - ) - if settled_count < fill_count: - raise KalshiBrokerTruthError( - "settlement count does not cover the filled exposure" - ) - return { - "state": "SETTLED_POSITION_ABSENT", - "positions": [], - "settlement": settlement, - } - - def settlement_reconciliation_witness( - self, - position_exposure: Mapping[str, Any], - ) -> Mapping[str, Any] | None: - """Return a signed settlement/position-close witness when complete.""" - first = self._settlement_projection(position_exposure) - second = self._settlement_projection(position_exposure) - if canonical_json(first) != canonical_json(second): - raise KalshiBrokerTruthError( - "position or settlement state changed during reconciliation" - ) - if first["state"] != "SETTLED_POSITION_ABSENT": - return None - observed = self._broker_truth._now() - settlement = first["settlement"] - projection_digest = sha256_json( - { - "schema": "dummy.kalshi-settlement-projection.v1", - "projection": first, - } - ) - invariant = { - "venue": "dummy_kalshi", - "account_hash": self._broker_truth._expected_account_hash, - "subaccount_number": ( - self._broker_truth._subaccount_number - ), - "position_exposure_id": position_exposure.get( - "position_exposure_id" - ), - "settlement": settlement, - "position_absent": True, - } - body = { - "schema": SETTLEMENT_WITNESS_SCHEMA, - "witness_id": sha256_json(invariant), - "venue": "dummy_kalshi", - "account_hash": self._broker_truth._expected_account_hash, - "subaccount_number": ( - self._broker_truth._subaccount_number - ), - "position_exposure_id": _identifier( - position_exposure.get("position_exposure_id"), - field="position_exposure.position_exposure_id", - ), - "reservation_id": _identifier( - position_exposure.get("reservation_id"), - field="position_exposure.reservation_id", - ), - "proposal_id": _identifier( - position_exposure.get("proposal_id"), - field="position_exposure.proposal_id", - ), - "contract_ticker": settlement["ticker"], - "side": position_exposure.get("side"), - "fill_count": _integer( - position_exposure.get("fill_count"), - field="position_exposure.fill_count", - minimum=1, - ), - "market_result": settlement["market_result"], - "settled_at": settlement["settled_time"], - "revenue_cents": settlement["revenue_cents"], - "settlement_fee_cents": ( - _dollars_to_conservative_cents( - Decimal(str(settlement["fee_cost_dollars"])), - field="settlement_fee_cents", - ) - ), - "position_absent": True, - "observed_at": _format_utc(observed), - "broker_projection_sha256": projection_digest, - } - return sign_broker_witness( - body, - private_key=self._witness_signing_private_key, - observed_at=observed, - correlation_id=body["proposal_id"], - ) - - -__all__ = ["KalshiReconciliationReader"] diff --git a/live_firewall/operational_journal.py b/live_firewall/operational_journal.py deleted file mode 100644 index bac4c225..00000000 --- a/live_firewall/operational_journal.py +++ /dev/null @@ -1,414 +0,0 @@ -"""Compact append-only operational journal and durable outbox. - -This journal is intentionally separate from Dummy's high-volume research -ledger. It records only low-volume authority, reservation, bootstrap, and -reconciliation facts needed at the live boundary. A broken hash chain is an -authority failure: callers can inspect the journal, but cannot append through -an unhealthy instance. -""" -from __future__ import annotations - -import hashlib -import json -import os -import threading -from contextlib import contextmanager -from collections.abc import Callable, Mapping -from datetime import datetime, timezone -from pathlib import Path -from typing import Any, BinaryIO, Iterator, cast - - -OPERATIONAL_EVENT_SCHEMA = "dummy.operational-event.v1" - - -def canonical_json(value: Any) -> str: - """Return the shared DumbMoney canonical JSON representation.""" - return json.dumps( - value, - sort_keys=True, - separators=(",", ":"), - ensure_ascii=False, - allow_nan=False, - ) - - -def sha256_json(value: Any) -> str: - return hashlib.sha256(canonical_json(value).encode("utf-8")).hexdigest() - - -class OperationalJournalError(RuntimeError): - """Raised when an append-only journal cannot prove its own history.""" - - -class AppendOnlyOperationalJournal: - """Hash-chained JSONL journal with serialized cross-process appends.""" - - def __init__( - self, - path: Path, - *, - now_fn: Callable[[], datetime] | None = None, - ) -> None: - self.path = Path(path) - self._now_fn = now_fn or (lambda: datetime.now(timezone.utc)) - self._lock = threading.RLock() - self._operation_lock = threading.RLock() - self._lock_path = self.path.with_name(f"{self.path.name}.lock") - self._operation_lock_path = self.path.with_name( - f"{self.path.name}.operation.lock" - ) - self._events: list[dict[str, Any]] = [] - self._error: str | None = None - self._load() - - @property - def healthy(self) -> bool: - return self._error is None - - @property - def error(self) -> str | None: - return self._error - - def events(self, *, kind: str | None = None) -> tuple[dict[str, Any], ...]: - with self._lock: - self._refresh_or_raise() - rows = list(self._events) - if kind is not None: - rows = [row for row in rows if row.get("kind") == kind] - # Canonical round-trip prevents callers from mutating journal state. - return tuple(json.loads(canonical_json(row)) for row in rows) - - def head(self) -> tuple[int, str]: - """Return the verified monotonic sequence and chain head.""" - with self._lock: - self._refresh_or_raise() - if not self._events: - return 0, "0" * 64 - latest = self._events[-1] - return int(latest["sequence"]), str(latest["event_sha256"]) - - def _load(self) -> None: - try: - with self._lock: - with self._interprocess_lock(): - self._reload_locked() - except Exception as exc: - self._error = f"{type(exc).__name__}: {exc}" - - @staticmethod - @contextmanager - def _lock_file(handle: BinaryIO) -> Iterator[None]: - handle.seek(0) - if os.name == "nt": - import msvcrt - - msvcrt.locking(handle.fileno(), msvcrt.LK_LOCK, 1) - try: - yield - finally: - handle.seek(0) - msvcrt.locking(handle.fileno(), msvcrt.LK_UNLCK, 1) - return - - import fcntl - - fcntl.flock( # type: ignore[attr-defined] - handle.fileno(), - fcntl.LOCK_EX, # type: ignore[attr-defined] - ) - try: - yield - finally: - fcntl.flock( # type: ignore[attr-defined] - handle.fileno(), - fcntl.LOCK_UN, # type: ignore[attr-defined] - ) - - @contextmanager - def _interprocess_lock(self) -> Iterator[None]: - """Lock a stable sidecar byte for the full reload/append transaction.""" - self.path.parent.mkdir(parents=True, exist_ok=True) - with self._lock_path.open("a+b") as handle: - handle.seek(0, os.SEEK_END) - if handle.tell() == 0: - handle.write(b"\0") - handle.flush() - os.fsync(handle.fileno()) - with self._lock_file(handle): - yield - - @contextmanager - def serialized_operation(self) -> Iterator[None]: - """Serialize a caller-owned multi-step operation across processes. - - This lock is deliberately separate from the append lock so the caller - may safely perform journal reads/appends while holding it. - """ - with self._operation_lock: - self.path.parent.mkdir(parents=True, exist_ok=True) - with self._operation_lock_path.open("a+b") as handle: - handle.seek(0, os.SEEK_END) - if handle.tell() == 0: - handle.write(b"\0") - handle.flush() - os.fsync(handle.fileno()) - with self._lock_file(handle): - yield - - def _reload_locked(self) -> None: - raw = self.path.read_bytes() if self.path.exists() else b"" - if raw and not raw.endswith(b"\n"): - raise OperationalJournalError("journal has a partial trailing record") - previous = "0" * 64 - expected_sequence = 1 - rows: list[dict[str, Any]] = [] - for line in raw.splitlines(): - if not line: - raise OperationalJournalError("journal contains a blank record") - value = json.loads(line.decode("utf-8")) - if not isinstance(value, dict): - raise OperationalJournalError("journal record must be an object") - if value.get("schema") != OPERATIONAL_EVENT_SCHEMA: - raise OperationalJournalError("journal schema mismatch") - if value.get("sequence") != expected_sequence: - raise OperationalJournalError("journal sequence mismatch") - if value.get("previous_sha256") != previous: - raise OperationalJournalError("journal previous hash mismatch") - claimed = str(value.get("event_sha256") or "") - unsigned = { - key: item for key, item in value.items() if key != "event_sha256" - } - actual = sha256_json(unsigned) - if claimed != actual: - raise OperationalJournalError("journal event hash mismatch") - # Reject non-canonical encodings so two readers cannot hash - # semantically equivalent but byte-distinct histories. - if line.decode("utf-8") != canonical_json(value): - raise OperationalJournalError("journal record is not canonical JSON") - rows.append(value) - previous = claimed - expected_sequence += 1 - self._events = rows - - def _refresh_or_raise(self) -> None: - if self._error is not None: - raise OperationalJournalError( - f"operational journal unhealthy: {self._error}" - ) - try: - with self._interprocess_lock(): - self._reload_locked() - except Exception as exc: - self._error = f"{type(exc).__name__}: {exc}" - raise OperationalJournalError( - f"operational journal refresh failed: {type(exc).__name__}" - ) from exc - - def append( - self, - kind: str, - payload: Mapping[str, Any], - *, - outbox_id: str | None = None, - allow_existing_outbox: bool = True, - validate_existing: ( - Callable[[tuple[dict[str, Any], ...]], None] | None - ) = None, - validate_existing_latest_kinds: tuple[str, ...] | None = None, - ) -> dict[str, Any]: - """Append and fsync one fact. - - ``outbox_id`` is globally idempotent. Repeating the identical event - returns the original event; reusing the id for different content fails. - Callers acquiring one-shot authority may set - ``allow_existing_outbox=False`` so even an identical prior event is a - failed claim rather than apparent ownership. - ``validate_existing`` runs against an immutable current snapshot while - the cross-process writer lock is held, immediately before the append. - It must not call back into this journal. - When ``validate_existing_latest_kinds`` is supplied, that snapshot is - bounded to at most the latest row for each named kind. Omitting it - preserves the full-history callback contract. - """ - with self._lock: - if self._error is not None: - raise OperationalJournalError( - f"operational journal unhealthy: {self._error}" - ) - if not isinstance(kind, str) or not kind.strip(): - raise ValueError("journal kind is required") - normalized_payload = json.loads(canonical_json(dict(payload))) - normalized_outbox = str(outbox_id).strip() if outbox_id is not None else None - if normalized_outbox == "": - raise ValueError("outbox_id cannot be blank") - normalized_latest_kinds: tuple[str, ...] | None = None - if validate_existing_latest_kinds is not None: - if validate_existing is None: - raise ValueError( - "validate_existing_latest_kinds requires " - "validate_existing" - ) - if not isinstance(validate_existing_latest_kinds, tuple): - raise TypeError( - "validate_existing_latest_kinds must be a tuple" - ) - if not 1 <= len(validate_existing_latest_kinds) <= 64: - raise ValueError( - "validate_existing_latest_kinds must contain " - "1 to 64 kinds" - ) - latest_kinds: list[str] = [] - for latest_kind in validate_existing_latest_kinds: - if ( - not isinstance(latest_kind, str) - or not latest_kind.strip() - ): - raise ValueError( - "validation kind must be a non-blank string" - ) - if latest_kind not in latest_kinds: - latest_kinds.append(latest_kind) - normalized_latest_kinds = tuple(latest_kinds) - try: - with self._interprocess_lock(): - try: - self._reload_locked() - except Exception as exc: - self._error = f"{type(exc).__name__}: {exc}" - raise OperationalJournalError( - "operational journal integrity refresh failed" - ) from exc - if normalized_outbox is not None: - existing = next( - ( - row - for row in self._events - if row.get("outbox_id") == normalized_outbox - ), - None, - ) - if existing is not None: - if not allow_existing_outbox: - raise OperationalJournalError( - "outbox id is already claimed" - ) - if ( - existing.get("kind") == kind - and existing.get("payload") == normalized_payload - ): - return cast( - dict[str, Any], - json.loads(canonical_json(existing)), - ) - raise OperationalJournalError( - "outbox id reused with different content" - ) - if validate_existing is not None: - validation_rows = self._events - if normalized_latest_kinds is not None: - latest_by_kind: dict[str, dict[str, Any]] = {} - for row in self._events: - row_kind = row.get("kind") - if row_kind in normalized_latest_kinds: - latest_by_kind[str(row_kind)] = row - validation_rows = sorted( - latest_by_kind.values(), - key=lambda row: int(row["sequence"]), - ) - snapshot = tuple( - json.loads(canonical_json(row)) - for row in validation_rows - ) - validate_existing(snapshot) - - now = self._now_fn() - if now.tzinfo is None or now.utcoffset() is None: - raise ValueError("journal clock must be timezone-aware") - event: dict[str, Any] = { - "schema": OPERATIONAL_EVENT_SCHEMA, - "sequence": len(self._events) + 1, - "recorded_at": now.astimezone(timezone.utc) - .isoformat() - .replace("+00:00", "Z"), - "kind": kind, - "payload": normalized_payload, - "previous_sha256": ( - str(self._events[-1]["event_sha256"]) - if self._events - else "0" * 64 - ), - } - if normalized_outbox is not None: - event["outbox_id"] = normalized_outbox - event["event_sha256"] = sha256_json(event) - serialized = (canonical_json(event) + "\n").encode("utf-8") - try: - with self.path.open("ab") as journal_handle: - journal_handle.write(serialized) - journal_handle.flush() - os.fsync(journal_handle.fileno()) - except OSError as exc: - self._error = f"{type(exc).__name__}: {exc}" - raise OperationalJournalError( - f"operational journal append failed: {type(exc).__name__}" - ) from exc - self._events.append(event) - except OSError as exc: - self._error = f"{type(exc).__name__}: {exc}" - raise OperationalJournalError( - f"operational journal lock failed: {type(exc).__name__}" - ) from exc - return cast( - dict[str, Any], - json.loads(canonical_json(event)), - ) - - def acknowledge_outbox( - self, - outbox_id: str, - *, - acknowledgement: Mapping[str, Any] | None = None, - ) -> dict[str, Any]: - normalized = str(outbox_id).strip() - rows = self.events() - source = next( - (row for row in rows if row.get("outbox_id") == normalized), - None, - ) - if source is None: - raise OperationalJournalError("cannot acknowledge unknown outbox id") - payload = { - "outbox_id": normalized, - "source_event_sha256": source["event_sha256"], - "acknowledgement": dict(acknowledgement or {}), - } - return self.append( - "outbox.acknowledged", - payload, - outbox_id=f"ack:{normalized}", - ) - - def pending_outbox(self) -> tuple[dict[str, Any], ...]: - rows = self.events() - acknowledged = { - str(row.get("payload", {}).get("outbox_id")) - for row in rows - if row.get("kind") == "outbox.acknowledged" - } - return tuple( - json.loads(canonical_json(row)) - for row in rows - if row.get("outbox_id") - and row.get("kind") != "outbox.acknowledged" - and row["outbox_id"] not in acknowledged - ) - - -__all__ = [ - "AppendOnlyOperationalJournal", - "OPERATIONAL_EVENT_SCHEMA", - "OperationalJournalError", - "canonical_json", - "sha256_json", -] diff --git a/live_firewall/sqlite_operational_journal.py b/live_firewall/sqlite_operational_journal.py deleted file mode 100644 index 9b96718d..00000000 --- a/live_firewall/sqlite_operational_journal.py +++ /dev/null @@ -1,1215 +0,0 @@ -"""Durable SQLite WAL implementation of Dummy's operational journal. - -The JSONL journal remains useful as a compact reference implementation. This -module provides the production storage shape: indexed reads, an indexed -outbox, and cross-process compare-and-append semantics under -``BEGIN IMMEDIATE``. Events retain the exact canonical event schema and hash -chain used by :mod:`live_firewall.operational_journal`. - -SQLite is used as a transactional append log, not as mutable application -state. Triggers reject event updates and deletes, and a singleton metadata row -tracks the committed sequence and hash-chain head. A restart performs a -streaming full-chain verification; normal operations verify only the known -head and any newly committed tail. - -The internal chain detects mutation, truncation against its current metadata, -and schema corruption. Like the JSONL implementation, it cannot by itself -distinguish a byte-for-byte rollback to an older valid database snapshot. -Deployment that must resist privileged whole-file rollback needs a monotonic -head anchor outside this database (for example, a Core-signed checkpoint). -""" -from __future__ import annotations - -import json -import re -import sqlite3 -import threading -from collections.abc import Callable, Iterator, Mapping -from contextlib import contextmanager -from datetime import datetime, timezone -from pathlib import Path -from typing import Any, NoReturn, cast - -from live_firewall.operational_journal import ( - AppendOnlyOperationalJournal, - OPERATIONAL_EVENT_SCHEMA, - OperationalJournalError, - canonical_json, - sha256_json, -) - - -SQLITE_OPERATIONAL_JOURNAL_SCHEMA = "dummy.sqlite-operational-journal.v1" -_APPLICATION_ID = 0x444D4A31 # ASCII "DMJ1". -_SCHEMA_VERSION = 1 -_ZERO_SHA256 = "0" * 64 -_SHA256_RE = re.compile(r"^[0-9a-f]{64}$") -_EVENT_COLUMNS = ( - "sequence, kind, outbox_id, acknowledges_outbox_id, " - "previous_sha256, event_sha256, event_json" -) - -_CREATE_METADATA = f""" -CREATE TABLE journal_metadata ( - singleton INTEGER PRIMARY KEY CHECK (singleton = 1), - schema TEXT NOT NULL CHECK (schema = '{SQLITE_OPERATIONAL_JOURNAL_SCHEMA}'), - event_count INTEGER NOT NULL CHECK (event_count >= 0), - head_sha256 TEXT NOT NULL CHECK (length(head_sha256) = 64) -) -""".strip() - -_CREATE_EVENTS = """ -CREATE TABLE operational_events ( - sequence INTEGER PRIMARY KEY CHECK (sequence > 0), - kind TEXT NOT NULL CHECK (length(kind) > 0), - outbox_id TEXT UNIQUE, - acknowledges_outbox_id TEXT UNIQUE, - previous_sha256 TEXT NOT NULL CHECK (length(previous_sha256) = 64), - event_sha256 TEXT NOT NULL UNIQUE CHECK (length(event_sha256) = 64), - event_json TEXT NOT NULL -) -""".strip() - -_CREATE_KIND_INDEX = """ -CREATE INDEX operational_events_kind_sequence_idx -ON operational_events (kind, sequence) -""".strip() - -_CREATE_OUTBOX_INDEX = """ -CREATE INDEX operational_events_outbox_sequence_idx -ON operational_events (outbox_id, sequence) -WHERE outbox_id IS NOT NULL -""".strip() - -_CREATE_ACK_INDEX = """ -CREATE INDEX operational_events_ack_target_idx -ON operational_events (acknowledges_outbox_id) -WHERE acknowledges_outbox_id IS NOT NULL -""".strip() - -_CREATE_VALIDATE_INSERT_TRIGGER = """ -CREATE TRIGGER operational_events_validate_insert -BEFORE INSERT ON operational_events -BEGIN - SELECT CASE - WHEN NEW.sequence != ( - SELECT event_count + 1 - FROM journal_metadata - WHERE singleton = 1 - ) - THEN RAISE(ABORT, 'journal sequence mismatch') - END; - SELECT CASE - WHEN NEW.previous_sha256 != ( - SELECT head_sha256 - FROM journal_metadata - WHERE singleton = 1 - ) - THEN RAISE(ABORT, 'journal previous hash mismatch') - END; -END -""".strip() - -_CREATE_ADVANCE_HEAD_TRIGGER = """ -CREATE TRIGGER operational_events_advance_head -AFTER INSERT ON operational_events -BEGIN - UPDATE journal_metadata - SET event_count = NEW.sequence, - head_sha256 = NEW.event_sha256 - WHERE singleton = 1; -END -""".strip() - -_CREATE_NO_UPDATE_TRIGGER = """ -CREATE TRIGGER operational_events_no_update -BEFORE UPDATE ON operational_events -BEGIN - SELECT RAISE(ABORT, 'operational events are append-only'); -END -""".strip() - -_CREATE_NO_DELETE_TRIGGER = """ -CREATE TRIGGER operational_events_no_delete -BEFORE DELETE ON operational_events -BEGIN - SELECT RAISE(ABORT, 'operational events are append-only'); -END -""".strip() - -_SCHEMA_OBJECTS = { - "journal_metadata": ("table", _CREATE_METADATA), - "operational_events": ("table", _CREATE_EVENTS), - "operational_events_kind_sequence_idx": ("index", _CREATE_KIND_INDEX), - "operational_events_outbox_sequence_idx": ("index", _CREATE_OUTBOX_INDEX), - "operational_events_ack_target_idx": ("index", _CREATE_ACK_INDEX), - "operational_events_validate_insert": ( - "trigger", - _CREATE_VALIDATE_INSERT_TRIGGER, - ), - "operational_events_advance_head": ( - "trigger", - _CREATE_ADVANCE_HEAD_TRIGGER, - ), - "operational_events_no_update": ("trigger", _CREATE_NO_UPDATE_TRIGGER), - "operational_events_no_delete": ("trigger", _CREATE_NO_DELETE_TRIGGER), -} - - -def _normalized_sql(value: str) -> str: - return " ".join(value.split()).casefold() - - -def _validated_page( - *, - after_sequence: int, - limit: int | None, -) -> tuple[int, int | None]: - if isinstance(after_sequence, bool) or not isinstance(after_sequence, int): - raise TypeError("after_sequence must be an integer") - if after_sequence < 0: - raise ValueError("after_sequence cannot be negative") - if limit is not None: - if isinstance(limit, bool) or not isinstance(limit, int): - raise TypeError("limit must be an integer") - if limit <= 0: - raise ValueError("limit must be positive") - if limit > 9_223_372_036_854_775_807: - raise ValueError("limit exceeds SQLite integer range") - return after_sequence, limit - - -class SQLiteOperationalJournal(AppendOnlyOperationalJournal): - """Hash-chained operational journal backed by durable SQLite WAL. - - ``events`` and ``pending_outbox`` accept optional ``after_sequence`` and - ``limit`` arguments for bounded incremental consumers. Omitting them - preserves the return behavior of :class:`AppendOnlyOperationalJournal`. - The legacy ``validate_existing`` callback receives a real tuple for API - compatibility and therefore materializes history; high-volume consumers - should use indexed pages and a purpose-built transactional projection. - """ - - def __init__( - self, - path: Path, - *, - now_fn: Callable[[], datetime] | None = None, - busy_timeout_seconds: float = 5.0, - scan_batch_size: int = 256, - wal_autocheckpoint_pages: int = 256, - journal_size_limit_bytes: int = 64 * 1024 * 1024, - ) -> None: - self.path = Path(path) - self._now_fn = now_fn or (lambda: datetime.now(timezone.utc)) - if ( - isinstance(busy_timeout_seconds, bool) - or not isinstance(busy_timeout_seconds, (int, float)) - or not 0 < float(busy_timeout_seconds) <= 60 - ): - raise ValueError("busy_timeout_seconds must be in (0, 60]") - if ( - isinstance(scan_batch_size, bool) - or not isinstance(scan_batch_size, int) - or not 1 <= scan_batch_size <= 10_000 - ): - raise ValueError("scan_batch_size must be in [1, 10000]") - if ( - isinstance(wal_autocheckpoint_pages, bool) - or not isinstance(wal_autocheckpoint_pages, int) - or not 1 <= wal_autocheckpoint_pages <= 100_000 - ): - raise ValueError("wal_autocheckpoint_pages must be in [1, 100000]") - if ( - isinstance(journal_size_limit_bytes, bool) - or not isinstance(journal_size_limit_bytes, int) - or journal_size_limit_bytes < 1_048_576 - ): - raise ValueError("journal_size_limit_bytes must be at least 1 MiB") - - self._busy_timeout_seconds = float(busy_timeout_seconds) - self._scan_batch_size = scan_batch_size - self._wal_autocheckpoint_pages = wal_autocheckpoint_pages - self._journal_size_limit_bytes = journal_size_limit_bytes - self._lock = threading.RLock() - self._connection: sqlite3.Connection | None = None - self._error: str | None = None - self._closed = False - self._operation_depth = 0 - self._verified_sequence = 0 - self._verified_head = _ZERO_SHA256 - self._observed_data_version: int | None = None - self._observed_schema_version: int | None = None - - try: - self.path.parent.mkdir(parents=True, exist_ok=True) - self._connection = sqlite3.connect( - str(self.path), - timeout=self._busy_timeout_seconds, - isolation_level=None, - check_same_thread=False, - ) - self._connection.row_factory = sqlite3.Row - self._configure_connection(self._connection) - self._initialize_or_validate_schema(self._connection) - self._connection.execute("BEGIN") - try: - self._verify_full_chain_locked(self._connection) - ( - self._observed_data_version, - self._observed_schema_version, - ) = self._database_versions(self._connection) - self._connection.execute("COMMIT") - except BaseException: - self._rollback_quietly(self._connection) - raise - except Exception as exc: - self._error = f"{type(exc).__name__}: {exc}" - - @property - def healthy(self) -> bool: - with self._lock: - if self._error is not None or self._closed: - return False - try: - with self._transaction(write=False) as connection: - self._synchronize_integrity_locked(connection) - except Exception as exc: - if self._error is None: - self._error = f"{type(exc).__name__}: {exc}" - return False - return True - - @property - def error(self) -> str | None: - # Probe first so a metadata/head mutation is surfaced without requiring - # a separate read or append call. - _ = self.healthy - with self._lock: - if self._closed and self._error is None: - return "OperationalJournalError: operational journal is closed" - return self._error - - def close(self) -> None: - """Close this process-local connection. - - A journal must not be closed from inside ``serialized_operation``. - """ - with self._lock: - if self._closed: - return - if self._operation_depth: - raise OperationalJournalError( - "cannot close journal during serialized operation" - ) - connection = self._connection - self._connection = None - self._closed = True - if connection is not None: - connection.close() - - def __enter__(self) -> SQLiteOperationalJournal: - if not self.healthy: - raise OperationalJournalError( - f"operational journal unhealthy: {self.error}" - ) - return self - - def __exit__( - self, - exc_type: object, - exc_value: object, - traceback: object, - ) -> None: - del exc_type, exc_value, traceback - self.close() - - def events( - self, - *, - kind: str | None = None, - after_sequence: int = 0, - limit: int | None = None, - ) -> tuple[dict[str, Any], ...]: - """Return immutable event copies, optionally as a bounded page.""" - normalized_after, normalized_limit = _validated_page( - after_sequence=after_sequence, - limit=limit, - ) - if kind is not None and not isinstance(kind, str): - raise TypeError("kind must be a string or None") - - with self._lock: - self._raise_if_unavailable() - try: - with self._transaction(write=False) as connection: - self._synchronize_integrity_locked(connection) - clauses = ["sequence > ?"] - parameters: list[Any] = [normalized_after] - if kind is not None: - clauses.append("kind = ?") - parameters.append(kind) - sql = ( - f"SELECT {_EVENT_COLUMNS} FROM operational_events " - f"WHERE {' AND '.join(clauses)} ORDER BY sequence" - ) - if normalized_limit is not None: - sql += " LIMIT ?" - parameters.append(normalized_limit) - rows = connection.execute(sql, parameters).fetchall() - return tuple(self._copy_row(row) for row in rows) - except sqlite3.Error as exc: - self._poison_sqlite("operational journal read failed", exc) - - def head(self) -> tuple[int, str]: - """Return the integrity-verified committed sequence and chain head.""" - with self._lock: - self._raise_if_unavailable() - try: - with self._transaction(write=False) as connection: - self._synchronize_integrity_locked(connection) - return self._verified_sequence, self._verified_head - except sqlite3.Error as exc: - self._poison_sqlite( - "operational journal head read failed", - exc, - ) - - @contextmanager - def serialized_operation(self) -> Iterator[None]: - """Hold one cross-process writer transaction across caller operations.""" - with self._lock: - self._raise_if_unavailable() - if self._operation_depth: - self._operation_depth += 1 - try: - yield - finally: - self._operation_depth -= 1 - return - - connection = self._require_connection() - old_verified = self._verification_state() - begun = False - try: - connection.execute("BEGIN IMMEDIATE") - begun = True - self._synchronize_integrity_locked(connection) - self._operation_depth = 1 - try: - yield - finally: - self._operation_depth = 0 - connection.execute("COMMIT") - except sqlite3.Error as exc: - if begun: - self._rollback_quietly(connection) - self._restore_verification_state(old_verified) - self._poison_sqlite( - "operational journal serialized operation failed", - exc, - ) - except BaseException: - if begun: - self._rollback_quietly(connection) - self._restore_verification_state(old_verified) - raise - - def append( - self, - kind: str, - payload: Mapping[str, Any], - *, - outbox_id: str | None = None, - allow_existing_outbox: bool = True, - validate_existing: ( - Callable[[tuple[dict[str, Any], ...]], None] | None - ) = None, - validate_existing_latest_kinds: tuple[str, ...] | None = None, - ) -> dict[str, Any]: - """Atomically validate current history and append one durable event. - - ``validate_existing_latest_kinds`` is an opt-in bounded validation - view. When supplied, ``validate_existing`` receives at most the latest - event for each named kind, in sequence order. This supports atomic - compare-and-swap on high-frequency state streams without repeatedly - materializing the full journal. Omitting it preserves the reference - journal's full-history callback contract. - """ - if not isinstance(kind, str) or not kind.strip(): - raise ValueError("journal kind is required") - normalized_validation_kinds = self._validated_latest_kinds( - validate_existing=validate_existing, - kinds=validate_existing_latest_kinds, - ) - normalized_payload = cast( - dict[str, Any], - json.loads(canonical_json(dict(payload))), - ) - normalized_outbox = ( - str(outbox_id).strip() if outbox_id is not None else None - ) - if normalized_outbox == "": - raise ValueError("outbox_id cannot be blank") - - with self._lock: - self._raise_if_unavailable() - try: - with self._transaction(write=True) as connection: - self._synchronize_integrity_locked(connection) - return self._append_locked( - connection, - kind=kind, - payload=normalized_payload, - outbox_id=normalized_outbox, - allow_existing_outbox=allow_existing_outbox, - validate_existing=validate_existing, - validate_existing_latest_kinds=( - normalized_validation_kinds - ), - ) - except sqlite3.Error as exc: - self._poison_sqlite("operational journal append failed", exc) - - def acknowledge_outbox( - self, - outbox_id: str, - *, - acknowledgement: Mapping[str, Any] | None = None, - ) -> dict[str, Any]: - normalized = str(outbox_id).strip() - with self._lock: - self._raise_if_unavailable() - try: - with self._transaction(write=True) as connection: - self._synchronize_integrity_locked(connection) - source_row = connection.execute( - f"SELECT {_EVENT_COLUMNS} FROM operational_events " - "WHERE outbox_id = ?", - (normalized,), - ).fetchone() - if source_row is None: - raise OperationalJournalError( - "cannot acknowledge unknown outbox id" - ) - source = self._copy_row(source_row) - payload = cast( - dict[str, Any], - json.loads( - canonical_json( - { - "outbox_id": normalized, - "source_event_sha256": source[ - "event_sha256" - ], - "acknowledgement": dict( - acknowledgement or {} - ), - } - ) - ), - ) - return self._append_locked( - connection, - kind="outbox.acknowledged", - payload=payload, - outbox_id=f"ack:{normalized}", - allow_existing_outbox=True, - validate_existing=None, - validate_existing_latest_kinds=None, - ) - except sqlite3.Error as exc: - self._poison_sqlite( - "operational journal acknowledgement failed", - exc, - ) - - def pending_outbox( - self, - *, - after_sequence: int = 0, - limit: int | None = None, - ) -> tuple[dict[str, Any], ...]: - """Return unacknowledged outbox events as an indexed bounded page.""" - normalized_after, normalized_limit = _validated_page( - after_sequence=after_sequence, - limit=limit, - ) - with self._lock: - self._raise_if_unavailable() - try: - with self._transaction(write=False) as connection: - self._synchronize_integrity_locked(connection) - sql = ( - f"SELECT {_EVENT_COLUMNS} " - "FROM operational_events AS source " - "WHERE source.sequence > ? " - "AND source.outbox_id IS NOT NULL " - "AND source.kind != 'outbox.acknowledged' " - "AND NOT EXISTS (" - " SELECT 1 FROM operational_events AS acknowledgement " - " WHERE acknowledgement.acknowledges_outbox_id = " - " source.outbox_id" - ") " - "ORDER BY source.sequence" - ) - parameters: list[Any] = [normalized_after] - if normalized_limit is not None: - sql += " LIMIT ?" - parameters.append(normalized_limit) - rows = connection.execute(sql, parameters).fetchall() - return tuple(self._copy_row(row) for row in rows) - except sqlite3.Error as exc: - self._poison_sqlite( - "operational journal outbox read failed", - exc, - ) - - @contextmanager - def _transaction( - self, - *, - write: bool, - ) -> Iterator[sqlite3.Connection]: - connection = self._require_connection() - if self._operation_depth: - yield connection - return - - old_verified = self._verification_state() - begun = False - try: - connection.execute("BEGIN IMMEDIATE" if write else "BEGIN") - begun = True - yield connection - connection.execute("COMMIT") - except BaseException: - if begun: - self._rollback_quietly(connection) - self._restore_verification_state(old_verified) - raise - - def _append_locked( - self, - connection: sqlite3.Connection, - *, - kind: str, - payload: dict[str, Any], - outbox_id: str | None, - allow_existing_outbox: bool, - validate_existing: ( - Callable[[tuple[dict[str, Any], ...]], None] | None - ), - validate_existing_latest_kinds: tuple[str, ...] | None, - ) -> dict[str, Any]: - if outbox_id is not None: - existing_row = connection.execute( - f"SELECT {_EVENT_COLUMNS} FROM operational_events " - "WHERE outbox_id = ?", - (outbox_id,), - ).fetchone() - if existing_row is not None: - existing = self._copy_row(existing_row) - if not allow_existing_outbox: - raise OperationalJournalError( - "outbox id is already claimed" - ) - if ( - existing.get("kind") == kind - and existing.get("payload") == payload - ): - return existing - raise OperationalJournalError( - "outbox id reused with different content" - ) - - if validate_existing is not None: - if validate_existing_latest_kinds is None: - validation_rows = self._all_events_locked(connection) - else: - validation_rows = self._latest_kinds_locked( - connection, - validate_existing_latest_kinds, - ) - validate_existing(validation_rows) - - now = self._now_fn() - if now.tzinfo is None or now.utcoffset() is None: - raise ValueError("journal clock must be timezone-aware") - sequence = self._verified_sequence + 1 - event: dict[str, Any] = { - "schema": OPERATIONAL_EVENT_SCHEMA, - "sequence": sequence, - "recorded_at": now.astimezone(timezone.utc) - .isoformat() - .replace("+00:00", "Z"), - "kind": kind, - "payload": payload, - "previous_sha256": self._verified_head, - } - if outbox_id is not None: - event["outbox_id"] = outbox_id - event["event_sha256"] = sha256_json(event) - event_json = canonical_json(event) - acknowledgement_target = self._acknowledgement_target(event) - - connection.execute( - """ - INSERT INTO operational_events ( - sequence, - kind, - outbox_id, - acknowledges_outbox_id, - previous_sha256, - event_sha256, - event_json - ) - VALUES (?, ?, ?, ?, ?, ?, ?) - """, - ( - sequence, - kind, - outbox_id, - acknowledgement_target, - self._verified_head, - event["event_sha256"], - event_json, - ), - ) - metadata = self._metadata_locked(connection) - if ( - metadata[0] != sequence - or metadata[1] != event["event_sha256"] - ): - self._integrity_failure("journal head trigger did not advance") - self._verified_sequence = sequence - self._verified_head = str(event["event_sha256"]) - return cast(dict[str, Any], json.loads(event_json)) - - def _all_events_locked( - self, - connection: sqlite3.Connection, - ) -> tuple[dict[str, Any], ...]: - cursor = connection.execute( - f"SELECT {_EVENT_COLUMNS} FROM operational_events " - "ORDER BY sequence" - ) - events: list[dict[str, Any]] = [] - while True: - rows = cursor.fetchmany(self._scan_batch_size) - if not rows: - break - events.extend(self._copy_row(row) for row in rows) - return tuple(events) - - def _latest_kinds_locked( - self, - connection: sqlite3.Connection, - kinds: tuple[str, ...], - ) -> tuple[dict[str, Any], ...]: - rows: list[dict[str, Any]] = [] - for kind in kinds: - row = connection.execute( - f"SELECT {_EVENT_COLUMNS} FROM operational_events " - "WHERE kind = ? ORDER BY sequence DESC LIMIT 1", - (kind,), - ).fetchone() - if row is not None: - rows.append(self._copy_row(row)) - rows.sort(key=lambda event: int(event["sequence"])) - return tuple(rows) - - @staticmethod - def _validated_latest_kinds( - *, - validate_existing: ( - Callable[[tuple[dict[str, Any], ...]], None] | None - ), - kinds: tuple[str, ...] | None, - ) -> tuple[str, ...] | None: - if kinds is None: - return None - if validate_existing is None: - raise ValueError( - "validate_existing_latest_kinds requires validate_existing" - ) - if not isinstance(kinds, tuple): - raise TypeError( - "validate_existing_latest_kinds must be a tuple" - ) - if not 1 <= len(kinds) <= 64: - raise ValueError( - "validate_existing_latest_kinds must contain 1 to 64 kinds" - ) - normalized: list[str] = [] - for kind in kinds: - if not isinstance(kind, str) or not kind.strip(): - raise ValueError("validation kind must be a non-blank string") - if kind not in normalized: - normalized.append(kind) - return tuple(normalized) - - def _copy_row(self, row: sqlite3.Row) -> dict[str, Any]: - event = self._decode_row(row) - return cast(dict[str, Any], json.loads(canonical_json(event))) - - def _decode_row( - self, - row: sqlite3.Row, - *, - expected_sequence: int | None = None, - expected_previous: str | None = None, - ) -> dict[str, Any]: - event_json = row["event_json"] - if not isinstance(event_json, str): - self._integrity_failure("journal event JSON is not text") - try: - value = json.loads(event_json) - except (TypeError, ValueError) as exc: - self._integrity_failure( - f"journal event JSON is invalid: {type(exc).__name__}" - ) - if not isinstance(value, dict): - self._integrity_failure("journal event must be an object") - event = cast(dict[str, Any], value) - try: - is_canonical = canonical_json(event) == event_json - except (TypeError, ValueError) as exc: - self._integrity_failure( - f"journal event cannot be canonicalized: {type(exc).__name__}" - ) - if not is_canonical: - self._integrity_failure("journal event is not canonical JSON") - if event.get("schema") != OPERATIONAL_EVENT_SCHEMA: - self._integrity_failure("journal event schema mismatch") - - sequence = event.get("sequence") - if isinstance(sequence, bool) or not isinstance(sequence, int): - self._integrity_failure("journal event sequence is invalid") - if sequence != row["sequence"]: - self._integrity_failure("journal event sequence column mismatch") - if expected_sequence is not None and sequence != expected_sequence: - self._integrity_failure("journal sequence mismatch") - - kind = event.get("kind") - if kind != row["kind"]: - self._integrity_failure("journal event kind column mismatch") - event_outbox = event.get("outbox_id") - if event_outbox != row["outbox_id"]: - self._integrity_failure("journal event outbox column mismatch") - - previous = event.get("previous_sha256") - if previous != row["previous_sha256"]: - self._integrity_failure( - "journal event previous hash column mismatch" - ) - if expected_previous is not None and previous != expected_previous: - self._integrity_failure("journal previous hash mismatch") - if not isinstance(previous, str) or _SHA256_RE.fullmatch(previous) is None: - self._integrity_failure("journal previous hash is invalid") - - claimed = event.get("event_sha256") - if claimed != row["event_sha256"]: - self._integrity_failure("journal event hash column mismatch") - if not isinstance(claimed, str) or _SHA256_RE.fullmatch(claimed) is None: - self._integrity_failure("journal event hash is invalid") - unsigned = { - key: item for key, item in event.items() if key != "event_sha256" - } - if sha256_json(unsigned) != claimed: - self._integrity_failure("journal event hash mismatch") - - if self._acknowledgement_target(event) != row[ - "acknowledges_outbox_id" - ]: - self._integrity_failure( - "journal acknowledgement target column mismatch" - ) - return event - - @staticmethod - def _acknowledgement_target(event: Mapping[str, Any]) -> str | None: - if event.get("kind") != "outbox.acknowledged": - return None - payload = event.get("payload") - if not isinstance(payload, Mapping): - return "None" - return str(payload.get("outbox_id")) - - def _synchronize_integrity_locked( - self, - connection: sqlite3.Connection, - ) -> None: - try: - self._validate_database_identity_locked(connection) - except OperationalJournalError as exc: - self._integrity_failure(str(exc)) - data_version, schema_version = self._database_versions(connection) - schema_changed = ( - self._observed_schema_version is not None - and schema_version != self._observed_schema_version - ) - data_changed = ( - self._observed_data_version is not None - and data_version != self._observed_data_version - ) - if schema_changed: - try: - self._validate_schema_objects_locked(connection) - except OperationalJournalError as exc: - self._integrity_failure(str(exc)) - if data_changed or schema_changed: - self._verify_full_chain_locked(connection) - self._observed_data_version = data_version - self._observed_schema_version = schema_version - return - - count, head = self._metadata_locked(connection) - if count < self._verified_sequence: - self._integrity_failure("journal event count moved backwards") - if count == self._verified_sequence: - if head != self._verified_head: - self._integrity_failure("journal head metadata mismatch") - if count == 0: - unexpected = connection.execute( - "SELECT 1 FROM operational_events LIMIT 1" - ).fetchone() - if unexpected is not None: - self._integrity_failure( - "journal contains events behind an empty head" - ) - self._observed_data_version = data_version - self._observed_schema_version = schema_version - return - head_row = connection.execute( - f"SELECT {_EVENT_COLUMNS} FROM operational_events " - "WHERE sequence = ?", - (count,), - ).fetchone() - if head_row is None: - self._integrity_failure("journal head event is missing") - decoded = self._decode_row( - cast(sqlite3.Row, head_row), - expected_sequence=count, - ) - if decoded["event_sha256"] != head: - self._integrity_failure("journal head event hash mismatch") - self._observed_data_version = data_version - self._observed_schema_version = schema_version - return - - previous = self._verified_head - expected_sequence = self._verified_sequence + 1 - if self._verified_sequence: - anchor = connection.execute( - f"SELECT {_EVENT_COLUMNS} FROM operational_events " - "WHERE sequence = ?", - (self._verified_sequence,), - ).fetchone() - if anchor is None: - self._integrity_failure("verified journal anchor is missing") - anchor_event = self._decode_row( - cast(sqlite3.Row, anchor), - expected_sequence=self._verified_sequence, - ) - if anchor_event["event_sha256"] != self._verified_head: - self._integrity_failure("verified journal anchor changed") - - cursor = connection.execute( - f"SELECT {_EVENT_COLUMNS} FROM operational_events " - "WHERE sequence > ? ORDER BY sequence", - (self._verified_sequence,), - ) - observed = self._verified_sequence - while True: - rows = cursor.fetchmany(self._scan_batch_size) - if not rows: - break - for row in rows: - event = self._decode_row( - row, - expected_sequence=expected_sequence, - expected_previous=previous, - ) - previous = str(event["event_sha256"]) - observed = expected_sequence - expected_sequence += 1 - if observed != count: - self._integrity_failure("journal metadata count mismatch") - if previous != head: - self._integrity_failure("journal metadata head mismatch") - self._verified_sequence = count - self._verified_head = head - self._observed_data_version = data_version - self._observed_schema_version = schema_version - - def _verify_full_chain_locked( - self, - connection: sqlite3.Connection, - ) -> None: - quick_check = connection.execute("PRAGMA quick_check(1)").fetchone() - if quick_check is None or str(quick_check[0]).casefold() != "ok": - self._integrity_failure("SQLite quick_check failed") - - expected_sequence = 1 - previous = _ZERO_SHA256 - cursor = connection.execute( - f"SELECT {_EVENT_COLUMNS} FROM operational_events " - "ORDER BY sequence" - ) - while True: - rows = cursor.fetchmany(self._scan_batch_size) - if not rows: - break - for row in rows: - event = self._decode_row( - row, - expected_sequence=expected_sequence, - expected_previous=previous, - ) - previous = str(event["event_sha256"]) - expected_sequence += 1 - observed_count = expected_sequence - 1 - metadata_count, metadata_head = self._metadata_locked(connection) - if metadata_count != observed_count: - self._integrity_failure("journal metadata count mismatch") - if metadata_head != previous: - self._integrity_failure("journal metadata head mismatch") - self._verified_sequence = observed_count - self._verified_head = previous - - def _metadata_locked( - self, - connection: sqlite3.Connection, - ) -> tuple[int, str]: - rows = connection.execute( - "SELECT schema, event_count, head_sha256 " - "FROM journal_metadata WHERE singleton = 1" - ).fetchall() - if len(rows) != 1: - self._integrity_failure("journal metadata row is missing") - row = rows[0] - if row["schema"] != SQLITE_OPERATIONAL_JOURNAL_SCHEMA: - self._integrity_failure("journal metadata schema mismatch") - count = row["event_count"] - head = row["head_sha256"] - if isinstance(count, bool) or not isinstance(count, int) or count < 0: - self._integrity_failure("journal metadata count is invalid") - if not isinstance(head, str) or _SHA256_RE.fullmatch(head) is None: - self._integrity_failure("journal metadata head is invalid") - if count == 0 and head != _ZERO_SHA256: - self._integrity_failure("empty journal head is not zero") - if count > 0 and head == _ZERO_SHA256: - self._integrity_failure("non-empty journal head is zero") - return count, head - - def _configure_connection(self, connection: sqlite3.Connection) -> None: - timeout_ms = max(1, int(self._busy_timeout_seconds * 1000)) - connection.execute(f"PRAGMA busy_timeout = {timeout_ms}") - mode = connection.execute("PRAGMA journal_mode = WAL").fetchone() - if mode is None or str(mode[0]).casefold() != "wal": - raise OperationalJournalError( - "SQLite refused WAL journal mode" - ) - connection.execute("PRAGMA synchronous = FULL") - connection.execute("PRAGMA fullfsync = ON") - connection.execute("PRAGMA checkpoint_fullfsync = ON") - connection.execute("PRAGMA foreign_keys = ON") - connection.execute("PRAGMA trusted_schema = OFF") - connection.execute("PRAGMA temp_store = MEMORY") - connection.execute( - f"PRAGMA wal_autocheckpoint = {self._wal_autocheckpoint_pages}" - ) - connection.execute( - f"PRAGMA journal_size_limit = {self._journal_size_limit_bytes}" - ) - - def _initialize_or_validate_schema( - self, - connection: sqlite3.Connection, - ) -> None: - connection.execute("BEGIN IMMEDIATE") - try: - tables = { - str(row[0]) - for row in connection.execute( - "SELECT name FROM sqlite_master " - "WHERE type = 'table' AND name NOT LIKE 'sqlite_%'" - ) - } - application_id = int( - connection.execute("PRAGMA application_id").fetchone()[0] - ) - user_version = int( - connection.execute("PRAGMA user_version").fetchone()[0] - ) - if not tables: - if application_id not in (0, _APPLICATION_ID): - raise OperationalJournalError( - "SQLite application id mismatch" - ) - if user_version not in (0, _SCHEMA_VERSION): - raise OperationalJournalError( - "SQLite schema version mismatch" - ) - for _object_type, statement in _SCHEMA_OBJECTS.values(): - connection.execute(statement) - connection.execute( - "INSERT INTO journal_metadata " - "(singleton, schema, event_count, head_sha256) " - "VALUES (1, ?, 0, ?)", - (SQLITE_OPERATIONAL_JOURNAL_SCHEMA, _ZERO_SHA256), - ) - connection.execute(f"PRAGMA application_id = {_APPLICATION_ID}") - connection.execute(f"PRAGMA user_version = {_SCHEMA_VERSION}") - else: - if application_id != _APPLICATION_ID: - raise OperationalJournalError( - "SQLite application id mismatch" - ) - if user_version != _SCHEMA_VERSION: - raise OperationalJournalError( - "SQLite schema version mismatch" - ) - if tables != {"journal_metadata", "operational_events"}: - raise OperationalJournalError( - "SQLite journal contains unexpected tables" - ) - self._validate_schema_objects_locked(connection) - connection.execute("COMMIT") - except BaseException: - self._rollback_quietly(connection) - raise - - def _validate_schema_objects_locked( - self, - connection: sqlite3.Connection, - ) -> None: - named_objects = { - str(row["name"]) - for row in connection.execute( - "SELECT name FROM sqlite_master " - "WHERE type IN ('table', 'index', 'trigger', 'view') " - "AND name NOT LIKE 'sqlite_%' " - "AND sql IS NOT NULL" - ) - } - if named_objects != set(_SCHEMA_OBJECTS): - unexpected = sorted(named_objects - set(_SCHEMA_OBJECTS)) - missing = sorted(set(_SCHEMA_OBJECTS) - named_objects) - raise OperationalJournalError( - "SQLite journal schema object set mismatch: " - f"unexpected={unexpected}, missing={missing}" - ) - rows = connection.execute( - "SELECT type, name, sql FROM sqlite_master " - "WHERE name IN ({})".format( - ",".join("?" for _ in _SCHEMA_OBJECTS) - ), - tuple(_SCHEMA_OBJECTS), - ).fetchall() - actual = { - str(row["name"]): ( - str(row["type"]), - _normalized_sql(str(row["sql"])), - ) - for row in rows - } - for name, (object_type, statement) in _SCHEMA_OBJECTS.items(): - expected = (object_type, _normalized_sql(statement)) - if actual.get(name) != expected: - raise OperationalJournalError( - f"SQLite journal schema object mismatch: {name}" - ) - - @staticmethod - def _validate_database_identity_locked( - connection: sqlite3.Connection, - ) -> None: - application_id = int( - connection.execute("PRAGMA application_id").fetchone()[0] - ) - if application_id != _APPLICATION_ID: - raise OperationalJournalError("SQLite application id mismatch") - user_version = int( - connection.execute("PRAGMA user_version").fetchone()[0] - ) - if user_version != _SCHEMA_VERSION: - raise OperationalJournalError("SQLite schema version mismatch") - - @staticmethod - def _database_versions( - connection: sqlite3.Connection, - ) -> tuple[int, int]: - data_version = int( - connection.execute("PRAGMA data_version").fetchone()[0] - ) - schema_version = int( - connection.execute("PRAGMA schema_version").fetchone()[0] - ) - return data_version, schema_version - - def _verification_state( - self, - ) -> tuple[int, str, int | None, int | None]: - return ( - self._verified_sequence, - self._verified_head, - self._observed_data_version, - self._observed_schema_version, - ) - - def _restore_verification_state( - self, - state: tuple[int, str, int | None, int | None], - ) -> None: - ( - self._verified_sequence, - self._verified_head, - self._observed_data_version, - self._observed_schema_version, - ) = state - - def _raise_if_unavailable(self) -> None: - if self._closed: - raise OperationalJournalError("operational journal is closed") - if self._error is not None: - raise OperationalJournalError( - f"operational journal unhealthy: {self._error}" - ) - - def _require_connection(self) -> sqlite3.Connection: - self._raise_if_unavailable() - if self._connection is None: - raise OperationalJournalError( - "operational journal connection is unavailable" - ) - return self._connection - - def _integrity_failure(self, message: str) -> NoReturn: - self._error = f"OperationalJournalError: {message}" - raise OperationalJournalError(message) - - def _poison_sqlite( - self, - message: str, - exc: sqlite3.Error, - ) -> NoReturn: - self._error = f"{type(exc).__name__}: {exc}" - raise OperationalJournalError( - f"{message}: {type(exc).__name__}" - ) from exc - - @staticmethod - def _rollback_quietly(connection: sqlite3.Connection) -> None: - try: - if connection.in_transaction: - connection.execute("ROLLBACK") - except sqlite3.Error: - pass - - -__all__ = [ - "SQLITE_OPERATIONAL_JOURNAL_SCHEMA", - "SQLiteOperationalJournal", -] diff --git a/predator_mesh/brokers/kalshi_livebrokerfirewall_adapter.py b/predator_mesh/brokers/kalshi_livebrokerfirewall_adapter.py index 0f13f405..10780555 100644 --- a/predator_mesh/brokers/kalshi_livebrokerfirewall_adapter.py +++ b/predator_mesh/brokers/kalshi_livebrokerfirewall_adapter.py @@ -81,16 +81,19 @@ def __init__( self.max_order_notional_cents = int(max_order_notional_cents) self._attempted = False - # This retired adapter retains authenticated status reads only. Keep - # those reads on the same reviewed production origin and signature - # prefix as KalshiClient; ambient service variables are not endpoint - # authority. - self._base = kalshi.signer.BASE - self._version = kalshi.signer.VERSION + # Use the same defaults as kalshi.signer so the request URL and the + # signature prefix stay aligned. + self._base = _env("KALSHI_API_BASE") or kalshi.signer.BASE + self._version = _env("KALSHI_API_VERSION") or kalshi.signer.VERSION self._kalshi = KalshiClient() if httpx_client is not None: self._kalshi.client = httpx_client + else: + self._kalshi.client = httpx.AsyncClient( + base_url=f"{self._base}/{self._version}".rstrip("/"), + timeout=10, + ) # ------------------------------------------------------------------ # Environment / credentials diff --git a/tests/fixtures/dumbmoney/signed-capital-envelope.v1.json b/tests/fixtures/dumbmoney/signed-capital-envelope.v1.json deleted file mode 100644 index 7327a1dc..00000000 --- a/tests/fixtures/dumbmoney/signed-capital-envelope.v1.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "fixture_schema": "dumbmoney.signed-capital-envelope-fixture.v1", - "public_key_base64url": "A6EHv_POEL4dcN0Y50vAmWfk1jCbpQ1fHdyGZBJVMbg", - "signing_payload_sha256": "97f8ecdf0d6b48b310c06cdeb37654fb171f4fa62bf91b427965191643d7ee1e", - "envelope": { - "schema": "dumbmoney.signed-envelope.v1", - "source_id": "dumbmoney-core", - "source_sequence": 1, - "event_id": "95fd19cc7bcbc89fe3c7985ee04d502704344b2f09c1eb6dce575b41c0ae579c", - "correlation_id": "fixture-capital-001", - "causation_id": null, - "nonce": "fixture-nonce-001", - "not_before": "2099-01-01T00:00:00Z", - "expires_at": "2099-01-01T00:01:00Z", - "body_schema": "dumbmoney.capital-envelope.v1", - "body_digest": "fcf86b4c257c0fea9ba65051366b76738563598d4217c4950ef3cf63ed1927d0", - "body": { - "schema": "dumbmoney.capital-envelope.v1", - "envelope_id": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", - "mandate_id": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", - "venue": "dopey_robinhood", - "account_hash": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", - "strategy_hashes": [ - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - ], - "passport_hashes": [ - "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" - ], - "promotion_hashes": [ - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" - ], - "authorized_instruments": [ - "equity:ACME" - ], - "authorized_mode": "LIVE", - "max_order_risk_cents": 100, - "max_open_risk_cents": 1250, - "max_correlated_risk_cents": 300, - "max_daily_loss_cents": 300, - "max_open_orders": 5, - "fencing_generation": 7, - "policy_epoch": 1, - "not_before": "2099-01-01T00:00:00Z", - "expires_at": "2099-01-01T00:01:00Z" - }, - "signature_algorithm": "Ed25519", - "signer_key_id": "56475aa75463474c0285df5dbf2bcab73da651358839e9b77481b2eab107708c", - "signature": "ga9nH3SEc6uGk8U_Q-tqWXa76n_-OSq8VhUAPHlNdTp5jzGmcZkN8JIjXuhpidniz4NOuTjpPWUE9vvtiqQ7CQ" - } -} diff --git a/tests/test_autonomy_pipeline.py b/tests/test_autonomy_pipeline.py index eeca2580..afb4112c 100644 --- a/tests/test_autonomy_pipeline.py +++ b/tests/test_autonomy_pipeline.py @@ -648,10 +648,6 @@ def live_authority_verdict(self): async def submit(self, request, orderbook, forecast): return self._result - class FakeCapital: - def binding_for(self, **_kwargs): - return {} - from core.ontology import LiveOrderResult accepted = LiveOrderResult( @@ -663,7 +659,6 @@ def binding_for(self, **_kwargs): kill_path=tmp_path / "KILL", risk_state_path=brain.state_path, exchange_status_fn=lambda: {"exchange_active": True, "trading_active": True}, - capital_envelope_adapter=FakeCapital(), ) monkeypatch.setattr(executor, "_make_firewall", lambda: FakeFirewall(accepted)) outcome = asyncio.run(executor.execute(decision, market=market)) @@ -677,7 +672,6 @@ def binding_for(self, **_kwargs): SessionMode.LIVE, session_path=session, kill_path=tmp_path / "KILL", risk_state_path=brain.state_path, exchange_status_fn=lambda: {"exchange_active": True, "trading_active": True}, - capital_envelope_adapter=FakeCapital(), ) monkeypatch.setattr(executor2, "_make_firewall", lambda: FakeFirewall(rejected)) outcome2 = asyncio.run(executor2.execute(decision, market=market)) @@ -691,7 +685,6 @@ def binding_for(self, **_kwargs): SessionMode.LIVE, session_path=session, kill_path=tmp_path / "KILL", risk_state_path=brain.state_path, exchange_status_fn=lambda: {"exchange_active": True, "trading_active": True}, - capital_envelope_adapter=FakeCapital(), ) monkeypatch.setattr(executor3, "_make_firewall", lambda: FakeFirewall(local)) outcome3 = asyncio.run(executor3.execute(decision, market=market)) diff --git a/tests/test_dumbmoney_capital_envelope.py b/tests/test_dumbmoney_capital_envelope.py deleted file mode 100644 index 966d47bf..00000000 --- a/tests/test_dumbmoney_capital_envelope.py +++ /dev/null @@ -1,1969 +0,0 @@ -from __future__ import annotations - -import base64 -import copy -import hashlib -import json -import threading -from concurrent.futures import ThreadPoolExecutor -from datetime import datetime, timedelta, timezone -from decimal import Decimal -from pathlib import Path -from types import SimpleNamespace -from unittest.mock import AsyncMock, Mock - -import pytest -from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey - -from autonomy.kill_reconciliation import queue_kill_reconciliation -from autonomy.brain import PredatorBrain -from autonomy.ontology import OutcomeKind, SessionMode, TradeOutcome -from core.ontology import ( - AccountMode, - CapConfig, - Forecast, - FirewallVerdict, - LiveOrderRequest, - OrderBook, - OrderBookLevel, -) -from core.state import DummyState -from live_firewall.dumbmoney_capital import ( - CAPITAL_ENVELOPE_SCHEMA, - SIGNED_ENVELOPE_SCHEMA, - CapitalEnvelopeAdapter, - flat_book_receipt, - inherited_exposure_receipt, - strategy_binding_hash, - verify_signed_capital_envelope, -) -from live_firewall.dumbmoney_broker_witness import ( - SETTLEMENT_WITNESS_SCHEMA, - TERMINAL_WITNESS_SCHEMA, - sign_broker_witness, -) -from live_firewall.dumbmoney_reconciliation import ( - DumbMoneyKalshiReconciliationSweeper, -) -from live_firewall.exposure_tracker import ExposureTracker -from live_firewall.firewall import LiveBrokerFirewall -from live_firewall.operational_journal import ( - AppendOnlyOperationalJournal, - OperationalJournalError, - canonical_json, - sha256_json, -) - - -NOW = datetime(2026, 7, 26, 20, 0, 0, tzinfo=timezone.utc) -ACCOUNT_HASH = hashlib.sha256(b"dummy-kalshi-fixture-account").hexdigest() -STRATEGY_REFERENCE = "autonomy_strategy_v2:test-decision" -PASSPORT_REFERENCE = "autonomy_forecast:test-decision" -STRATEGY_HASH = strategy_binding_hash(STRATEGY_REFERENCE) -PASSPORT_HASH = strategy_binding_hash(PASSPORT_REFERENCE) -PROMOTION_HASH = hashlib.sha256(b"promotion:fixture").hexdigest() -AUTHORIZED_INSTRUMENT = "event_contract:KXTEST-26JUL" -PRIVATE_KEY = Ed25519PrivateKey.from_private_bytes(bytes(range(32))) -PUBLIC_KEY = PRIVATE_KEY.public_key().public_bytes_raw() -SIGNER_KEY_ID = hashlib.sha256(PUBLIC_KEY).hexdigest() -WITNESS_PRIVATE_KEY = Ed25519PrivateKey.from_private_bytes( - bytes(range(31, -1, -1)) -) -WITNESS_PUBLIC_KEY = ( - WITNESS_PRIVATE_KEY.public_key().public_bytes_raw() -) -WITNESS_KEY_ID = hashlib.sha256(WITNESS_PUBLIC_KEY).hexdigest() - - -class _FixtureLineageResolver: - def resolve_lineage( - self, - *, - capital, - strategy_hash, - passport_hash, - promotion_hash, - authorized_instrument, - expected_binding=None, - ): - evidence = { - "strategy_hash": strategy_hash, - "passport_hash": passport_hash, - "promotion_hash": promotion_hash, - "authorized_instrument": authorized_instrument, - "maximum_loss_cents": min( - 10_000, - capital.max_order_risk_cents, - ), - "policy_epoch": capital.policy_epoch, - "capital_envelope_id": capital.envelope_id, - "capital_event_id": capital.event_id, - "capital_body_digest": sha256_json(capital.body), - "capital_fencing_generation": capital.fencing_generation, - "passport_event_id": _hash(f"passport-event:{passport_hash}"), - "promotion_event_id": _hash(f"promotion-event:{promotion_hash}"), - "passport_signer_key_id": _hash("research-key"), - "promotion_signer_key_id": _hash("promoter-key"), - "expires_at": _z(capital.expires_at), - "passport_resolution_sha256": _hash("passport-resolution"), - "promotion_resolution_sha256": _hash("promotion-resolution"), - } - if expected_binding is not None: - expected = dict(expected_binding) - expected.pop("passport_resolution_sha256", None) - expected.pop("promotion_resolution_sha256", None) - actual = dict(evidence) - actual.pop("passport_resolution_sha256", None) - actual.pop("promotion_resolution_sha256", None) - if expected != actual: - raise ValueError("fixture lineage binding changed") - return SimpleNamespace(evidence=lambda: evidence) - - -LINEAGE_RESOLVER = _FixtureLineageResolver() - - -def _z(value: datetime) -> str: - return value.astimezone(timezone.utc).isoformat().replace("+00:00", "Z") - - -def _hash(label: str) -> str: - return hashlib.sha256(label.encode("utf-8")).hexdigest() - - -def _signed_envelope( - *, - source_sequence: int = 1, - nonce: str = "dummy-nonce-1", - fencing_generation: int = 1, - venue: str = "dummy_kalshi", - account_hash: str = ACCOUNT_HASH, - not_before: datetime = NOW - timedelta(seconds=10), - expires_at: datetime = NOW + timedelta(seconds=50), - max_order_risk_cents: int = 500, - max_open_risk_cents: int = 1_000, - max_correlated_risk_cents: int = 750, - max_daily_loss_cents: int = 300, - max_open_orders: int = 5, - policy_epoch: int = 1, - strategy_hashes: list[str] | None = None, - passport_hashes: list[str] | None = None, - promotion_hashes: list[str] | None = None, - authorized_instruments: list[str] | None = None, -) -> dict: - body = { - "schema": CAPITAL_ENVELOPE_SCHEMA, - "envelope_id": _hash( - f"envelope:{source_sequence}:{nonce}:{fencing_generation}" - ), - "mandate_id": _hash("mandate:fixture"), - "venue": venue, - "account_hash": account_hash, - "strategy_hashes": ( - [STRATEGY_HASH] if strategy_hashes is None else strategy_hashes - ), - "passport_hashes": ( - [PASSPORT_HASH] if passport_hashes is None else passport_hashes - ), - "promotion_hashes": ( - [PROMOTION_HASH] if promotion_hashes is None else promotion_hashes - ), - "authorized_instruments": ( - [AUTHORIZED_INSTRUMENT] - if authorized_instruments is None - else authorized_instruments - ), - "authorized_mode": "LIVE", - "max_order_risk_cents": max_order_risk_cents, - "max_open_risk_cents": max_open_risk_cents, - "max_correlated_risk_cents": max_correlated_risk_cents, - "max_daily_loss_cents": max_daily_loss_cents, - "max_open_orders": max_open_orders, - "fencing_generation": fencing_generation, - "policy_epoch": policy_epoch, - "not_before": _z(not_before), - "expires_at": _z(expires_at), - } - event_material = { - "schema": SIGNED_ENVELOPE_SCHEMA, - "source_id": "dumbmoney-core", - "source_sequence": source_sequence, - "correlation_id": "dummy-fixture-correlation", - "causation_id": None, - "nonce": nonce, - "not_before": body["not_before"], - "expires_at": body["expires_at"], - "body_schema": CAPITAL_ENVELOPE_SCHEMA, - "body_digest": sha256_json(body), - "body": body, - "signature_algorithm": "Ed25519", - "signer_key_id": SIGNER_KEY_ID, - } - wrapper = { - **event_material, - "event_id": sha256_json(event_material), - } - wrapper["signature"] = ( - base64.urlsafe_b64encode( - PRIVATE_KEY.sign(canonical_json(wrapper).encode("utf-8")) - ) - .decode("ascii") - .rstrip("=") - ) - return wrapper - - -def _adapter( - tmp_path: Path, - *, - now: datetime = NOW, -) -> tuple[CapitalEnvelopeAdapter, AppendOnlyOperationalJournal]: - def clock() -> datetime: - return now - - journal = AppendOnlyOperationalJournal( - tmp_path / "operational.jsonl", - now_fn=clock, - ) - adapter = CapitalEnvelopeAdapter( - journal=journal, - trusted_public_keys={SIGNER_KEY_ID: PUBLIC_KEY}, - expected_venue="dummy_kalshi", - expected_account_hash=ACCOUNT_HASH, - lineage_resolver=LINEAGE_RESOLVER, - trusted_broker_witness_public_keys={ - WITNESS_KEY_ID: WITNESS_PUBLIC_KEY - }, - now_fn=clock, - ) - return adapter, journal - - -def _record_flat(adapter: CapitalEnvelopeAdapter) -> None: - adapter.record_broker_bootstrap( - flat_book_receipt( - receipt_id=_hash("flat-receipt"), - venue="dummy_kalshi", - account_hash=ACCOUNT_HASH, - observed_at=_z(NOW), - broker_snapshot_sha256=_hash("flat-broker-snapshot"), - ) - ) - - -def _request( - wrapper: dict, - *, - proposal_id: str = "proposal-1", - market_ticker: str = "KXTEST-26JUL", - price_cents: int = 50, - size: int = 1, -) -> LiveOrderRequest: - return LiveOrderRequest( - proposal_id=proposal_id, - market_ticker=market_ticker, - contract_ticker=market_ticker, - side="yes", - price_cents=price_cents, - size=size, - strategy_proof_reference=STRATEGY_REFERENCE, - forecast_proof_reference=PASSPORT_REFERENCE, - adapter_name="kalshi_live_firewall_adapter", - expiration_ts=int( - (datetime.now(timezone.utc) + timedelta(hours=1)).timestamp() - ), - capital_envelope_id=wrapper["body"]["envelope_id"], - capital_strategy_hash=STRATEGY_HASH, - capital_passport_hash=PASSPORT_HASH, - capital_promotion_hash=PROMOTION_HASH, - capital_fencing_generation=wrapper["body"]["fencing_generation"], - ) - - -def _terminal_witness( - reservation: dict, - *, - fill_count: int = 1, - terminal_status: str = "executed", -) -> dict: - fill_ids = ["fill-1"] if fill_count else [] - fill_cost = fill_count * int(reservation["price_cents"]) - fee = 2 if fill_count else 0 - body = { - "schema": TERMINAL_WITNESS_SCHEMA, - "witness_id": _hash( - f"terminal:{reservation['reservation_id']}:{fill_count}" - ), - "venue": "dummy_kalshi", - "account_hash": ACCOUNT_HASH, - "subaccount_number": 0, - "reservation_id": reservation["reservation_id"], - "proposal_id": reservation["proposal_id"], - "order_id": "broker-order-1", - "market_ticker": reservation["market_ticker"], - "contract_ticker": reservation["contract_ticker"], - "side": reservation["side"], - "terminal_status": terminal_status, - "initial_count": reservation["size"], - "fill_count": fill_count, - "remaining_count": 0, - "fill_cost_cents": fill_cost, - "fee_cents": fee, - "average_fill_price_cents": ( - int(reservation["price_cents"]) if fill_count else None - ), - "fill_ids": fill_ids, - "observed_at": _z(NOW), - "broker_projection_sha256": _hash( - f"terminal-projection:{reservation['reservation_id']}" - ), - } - return sign_broker_witness( - body, - private_key=WITNESS_PRIVATE_KEY, - observed_at=NOW, - correlation_id=str(reservation["proposal_id"]), - ) - - -def _settlement_witness(position: dict) -> dict: - body = { - "schema": SETTLEMENT_WITNESS_SCHEMA, - "witness_id": _hash( - f"settlement:{position['position_exposure_id']}" - ), - "venue": "dummy_kalshi", - "account_hash": ACCOUNT_HASH, - "subaccount_number": 0, - "position_exposure_id": position["position_exposure_id"], - "reservation_id": position["reservation_id"], - "proposal_id": position["proposal_id"], - "contract_ticker": position["contract_ticker"], - "side": position["side"], - "fill_count": position["fill_count"], - "market_result": "yes", - "settled_at": _z(NOW), - "revenue_cents": 100, - "settlement_fee_cents": 0, - "position_absent": True, - "observed_at": _z(NOW), - "broker_projection_sha256": _hash( - f"settlement-projection:{position['position_exposure_id']}" - ), - } - return sign_broker_witness( - body, - private_key=WITNESS_PRIVATE_KEY, - observed_at=NOW, - correlation_id=str(position["proposal_id"]), - ) - - -def test_shared_blunder_fixture_verifies_byte_for_byte(): - fixture = json.loads( - ( - Path(__file__).parent - / "fixtures" - / "dumbmoney" - / "signed-capital-envelope.v1.json" - ).read_text(encoding="utf-8") - ) - wrapper = fixture["envelope"] - public_key = base64.urlsafe_b64decode( - fixture["public_key_base64url"] - + "=" * (-len(fixture["public_key_base64url"]) % 4) - ) - signed_material = { - key: value for key, value in wrapper.items() if key != "signature" - } - assert hashlib.sha256( - canonical_json(signed_material).encode("utf-8") - ).hexdigest() == fixture["signing_payload_sha256"] - - verified = verify_signed_capital_envelope( - wrapper, - trusted_public_keys={wrapper["signer_key_id"]: public_key}, - expected_venue="dopey_robinhood", - expected_account_hash=wrapper["body"]["account_hash"], - now=datetime(2099, 1, 1, 0, 0, 30, tzinfo=timezone.utc), - ) - - assert verified.event_id == wrapper["event_id"] - assert verified.envelope_id == wrapper["body"]["envelope_id"] - assert verified.fencing_generation == 7 - assert verified.promotion_hashes == ("f" * 64,) - assert verified.authorized_instruments == ("equity:ACME",) - - -def test_expired_envelope_and_bad_signature_fail_closed(): - wrapper = _signed_envelope() - with pytest.raises(ValueError, match="expired"): - verify_signed_capital_envelope( - wrapper, - trusted_public_keys={SIGNER_KEY_ID: PUBLIC_KEY}, - expected_venue="dummy_kalshi", - expected_account_hash=ACCOUNT_HASH, - now=NOW + timedelta(minutes=2), - ) - - tampered = copy.deepcopy(wrapper) - tampered["signature"] = ( - ("A" if wrapper["signature"][0] != "A" else "B") - + wrapper["signature"][1:] - ) - with pytest.raises(ValueError, match="signature invalid"): - verify_signed_capital_envelope( - tampered, - trusted_public_keys={SIGNER_KEY_ID: PUBLIC_KEY}, - expected_venue="dummy_kalshi", - expected_account_hash=ACCOUNT_HASH, - now=NOW, - ) - - -@pytest.mark.parametrize( - ("venue", "account_hash", "message"), - [ - ("dopey_robinhood", ACCOUNT_HASH, "venue mismatch"), - ("dummy_kalshi", _hash("wrong-account"), "account mismatch"), - ], -) -def test_signed_envelope_is_bound_to_exact_venue_and_account( - venue, - account_hash, - message, -): - wrapper = _signed_envelope(venue=venue, account_hash=account_hash) - with pytest.raises(ValueError, match=message): - verify_signed_capital_envelope( - wrapper, - trusted_public_keys={SIGNER_KEY_ID: PUBLIC_KEY}, - expected_venue="dummy_kalshi", - expected_account_hash=ACCOUNT_HASH, - now=NOW, - ) - - -def test_capital_envelope_requires_complete_lineage_and_ordered_limits(): - mismatched_lineage = _signed_envelope( - promotion_hashes=sorted( - [PROMOTION_HASH, _hash("promotion:extra")] - ) - ) - with pytest.raises(ValueError, match="hash counts must match"): - verify_signed_capital_envelope( - mismatched_lineage, - trusted_public_keys={SIGNER_KEY_ID: PUBLIC_KEY}, - expected_venue="dummy_kalshi", - expected_account_hash=ACCOUNT_HASH, - now=NOW, - ) - - multiple_lineages = _signed_envelope( - strategy_hashes=sorted([STRATEGY_HASH, _hash("strategy:extra")]), - passport_hashes=sorted([PASSPORT_HASH, _hash("passport:extra")]), - promotion_hashes=sorted( - [PROMOTION_HASH, _hash("promotion:extra")] - ), - ) - with pytest.raises(ValueError, match="exactly one"): - verify_signed_capital_envelope( - multiple_lineages, - trusted_public_keys={SIGNER_KEY_ID: PUBLIC_KEY}, - expected_venue="dummy_kalshi", - expected_account_hash=ACCOUNT_HASH, - now=NOW, - ) - - bad_limit_order = _signed_envelope( - max_order_risk_cents=500, - max_correlated_risk_cents=499, - ) - with pytest.raises(ValueError, match="internally inconsistent"): - verify_signed_capital_envelope( - bad_limit_order, - trusted_public_keys={SIGNER_KEY_ID: PUBLIC_KEY}, - expected_venue="dummy_kalshi", - expected_account_hash=ACCOUNT_HASH, - now=NOW, - ) - - -def test_exact_instrument_and_promotion_are_rechecked_at_sink(tmp_path): - adapter, _ = _adapter(tmp_path) - wrapper = _signed_envelope() - adapter.accept_signed_envelope(wrapper) - _record_flat(adapter) - - unauthorized_instrument = _request( - wrapper, - market_ticker="KXOTHER-26JUL", - ) - instrument_verdict = adapter.evaluate_request( - unauthorized_instrument, - current_daily_loss_cents=0, - ) - assert instrument_verdict.allow is False - assert "instrument is not authorized" in instrument_verdict.reason - - wrong_promotion = _request(wrapper).model_copy( - update={"capital_promotion_hash": _hash("wrong-promotion")} - ) - promotion_verdict = adapter.evaluate_request( - wrong_promotion, - current_daily_loss_cents=0, - ) - assert promotion_verdict.allow is False - assert "promotion hash mismatch" in promotion_verdict.reason - - -def test_replay_sequence_nonce_and_fencing_are_fail_closed(tmp_path): - adapter, journal = _adapter(tmp_path) - first = _signed_envelope() - adapter.accept_signed_envelope(first) - adapter.accept_signed_envelope(first) - assert len(journal.events(kind="capital.envelope.accepted")) == 1 - - with pytest.raises(ValueError, match="nonce replay"): - adapter.accept_signed_envelope( - _signed_envelope(source_sequence=2, nonce="dummy-nonce-1") - ) - with pytest.raises(ValueError, match="source sequence replay"): - adapter.accept_signed_envelope( - _signed_envelope(source_sequence=1, nonce="dummy-nonce-2") - ) - - newest = _signed_envelope( - source_sequence=2, - nonce="dummy-nonce-2", - fencing_generation=9, - ) - adapter.accept_signed_envelope(newest) - with pytest.raises(ValueError, match="not strictly increasing"): - adapter.accept_signed_envelope( - _signed_envelope( - source_sequence=3, - nonce="dummy-nonce-3", - fencing_generation=8, - ) - ) - - _record_flat(adapter) - stale = adapter.evaluate_request(first_request := _request(first), current_daily_loss_cents=0) - assert first_request.capital_fencing_generation == 1 - assert stale.allow is False - assert "stale" in stale.reason - - -def test_equal_fence_split_brain_is_rejected(tmp_path): - adapter, _ = _adapter(tmp_path) - adapter.accept_signed_envelope( - _signed_envelope( - source_sequence=1, - nonce="equal-fence-a", - fencing_generation=4, - ) - ) - - with pytest.raises(ValueError, match="not strictly increasing"): - adapter.accept_signed_envelope( - _signed_envelope( - source_sequence=2, - nonce="equal-fence-b", - fencing_generation=4, - ) - ) - - -def test_two_adapters_cannot_accept_conflicting_equal_fences(tmp_path): - path = tmp_path / "shared-capital.jsonl" - first_journal = AppendOnlyOperationalJournal(path, now_fn=lambda: NOW) - second_journal = AppendOnlyOperationalJournal(path, now_fn=lambda: NOW) - first_adapter = CapitalEnvelopeAdapter( - journal=first_journal, - trusted_public_keys={SIGNER_KEY_ID: PUBLIC_KEY}, - expected_venue="dummy_kalshi", - expected_account_hash=ACCOUNT_HASH, - lineage_resolver=LINEAGE_RESOLVER, - now_fn=lambda: NOW, - ) - second_adapter = CapitalEnvelopeAdapter( - journal=second_journal, - trusted_public_keys={SIGNER_KEY_ID: PUBLIC_KEY}, - expected_venue="dummy_kalshi", - expected_account_hash=ACCOUNT_HASH, - lineage_resolver=LINEAGE_RESOLVER, - now_fn=lambda: NOW, - ) - first = _signed_envelope( - source_sequence=1, - nonce="concurrent-fence-a", - fencing_generation=1, - ) - second = _signed_envelope( - source_sequence=2, - nonce="concurrent-fence-b", - fencing_generation=1, - ) - barrier = threading.Barrier(3) - - def attempt(adapter, envelope): - barrier.wait() - try: - adapter.accept_signed_envelope(envelope) - except ValueError: - return "rejected" - return "accepted" - - with ThreadPoolExecutor(max_workers=2) as executor: - futures = [ - executor.submit(attempt, first_adapter, first), - executor.submit(attempt, second_adapter, second), - ] - barrier.wait() - outcomes = [future.result() for future in futures] - - assert sorted(outcomes) == ["accepted", "rejected"] - restarted = AppendOnlyOperationalJournal(path, now_fn=lambda: NOW) - accepted = restarted.events(kind="capital.envelope.accepted") - assert restarted.healthy is True - assert len(accepted) == 1 - assert [row["payload"]["fencing_generation"] for row in accepted] == [1] - - -def test_policy_epoch_cannot_regress_under_a_higher_fence(tmp_path): - adapter, _ = _adapter(tmp_path) - adapter.accept_signed_envelope( - _signed_envelope( - source_sequence=1, - nonce="policy-two", - fencing_generation=1, - policy_epoch=2, - ) - ) - - with pytest.raises(ValueError, match="policy epoch regressed"): - adapter.accept_signed_envelope( - _signed_envelope( - source_sequence=2, - nonce="policy-one", - fencing_generation=2, - policy_epoch=1, - ) - ) - - -def test_expired_newer_fence_never_resurrects_older_grant(tmp_path): - clock_state = {"now": NOW} - - def clock() -> datetime: - return clock_state["now"] - - journal = AppendOnlyOperationalJournal( - tmp_path / "operational.jsonl", - now_fn=clock, - ) - adapter = CapitalEnvelopeAdapter( - journal=journal, - trusted_public_keys={SIGNER_KEY_ID: PUBLIC_KEY}, - expected_venue="dummy_kalshi", - expected_account_hash=ACCOUNT_HASH, - lineage_resolver=LINEAGE_RESOLVER, - now_fn=clock, - ) - older = _signed_envelope( - source_sequence=1, - nonce="older-fence", - fencing_generation=1, - expires_at=NOW + timedelta(seconds=50), - ) - newer = _signed_envelope( - source_sequence=2, - nonce="newer-fence", - fencing_generation=2, - expires_at=NOW + timedelta(seconds=20), - ) - adapter.accept_signed_envelope(older) - adapter.accept_signed_envelope(newer) - _record_flat(adapter) - clock_state["now"] = NOW + timedelta(seconds=30) - - with pytest.raises(ValueError, match="no active capital envelope"): - adapter.binding_for( - strategy_hash=STRATEGY_HASH, - passport_hash=PASSPORT_HASH, - authorized_instrument=AUTHORIZED_INSTRUMENT, - ) - stale = adapter.evaluate_request( - _request(older), - current_daily_loss_cents=0, - ) - assert stale.allow is False - assert "stale" in stale.reason - - -def test_missing_local_exposure_is_never_treated_as_flat(tmp_path): - adapter, _ = _adapter(tmp_path) - wrapper = _signed_envelope() - adapter.accept_signed_envelope(wrapper) - - verdict = adapter.evaluate_request( - _request(wrapper), - current_daily_loss_cents=0, - ) - - assert verdict.allow is False - assert verdict.rejected_by == "capital_broker_bootstrap" - assert "local absence is not flat" in verdict.reason - - -def test_daily_loss_capacity_charges_proposed_order_at_exact_boundary(tmp_path): - adapter, _ = _adapter(tmp_path) - wrapper = _signed_envelope(max_daily_loss_cents=300) - adapter.accept_signed_envelope(wrapper) - _record_flat(adapter) - request = _request(wrapper, price_cents=100) - - exact = adapter.evaluate_request( - request, - current_daily_loss_cents=200, - ) - over = adapter.evaluate_request( - request, - current_daily_loss_cents=201, - ) - - assert exact.allow is True - assert over.allow is False - assert "daily loss capacity" in over.reason - - -def test_broker_bootstrap_cannot_replay_an_older_snapshot(tmp_path): - adapter, journal = _adapter(tmp_path) - current = flat_book_receipt( - receipt_id=_hash("bootstrap-current"), - venue="dummy_kalshi", - account_hash=ACCOUNT_HASH, - observed_at=_z(NOW), - broker_snapshot_sha256=_hash("bootstrap-current-snapshot"), - ) - first = adapter.record_broker_bootstrap(current) - repeated = adapter.record_broker_bootstrap(current) - assert repeated["event_sha256"] == first["event_sha256"] - - older = flat_book_receipt( - receipt_id=_hash("bootstrap-older"), - venue="dummy_kalshi", - account_hash=ACCOUNT_HASH, - observed_at=_z(NOW - timedelta(seconds=1)), - broker_snapshot_sha256=_hash("bootstrap-older-snapshot"), - ) - with pytest.raises(ValueError, match="strictly increasing"): - adapter.record_broker_bootstrap(older) - assert len(journal.events(kind="broker.bootstrap.recorded")) == 1 - - -def test_two_adapters_cannot_record_conflicting_bootstrap_observations( - tmp_path, -): - path = tmp_path / "shared-bootstrap.jsonl" - adapters = [ - CapitalEnvelopeAdapter( - journal=AppendOnlyOperationalJournal( - path, - now_fn=lambda: NOW, - ), - trusted_public_keys={SIGNER_KEY_ID: PUBLIC_KEY}, - expected_venue="dummy_kalshi", - expected_account_hash=ACCOUNT_HASH, - lineage_resolver=LINEAGE_RESOLVER, - now_fn=lambda: NOW, - ) - for _ in range(2) - ] - receipts = [ - flat_book_receipt( - receipt_id=_hash(f"concurrent-bootstrap:{index}"), - venue="dummy_kalshi", - account_hash=ACCOUNT_HASH, - observed_at=_z(NOW), - broker_snapshot_sha256=_hash( - f"concurrent-bootstrap-snapshot:{index}" - ), - ) - for index in range(2) - ] - barrier = threading.Barrier(3) - - def attempt(adapter, receipt): - barrier.wait() - try: - adapter.record_broker_bootstrap(receipt) - except ValueError: - return "rejected" - return "accepted" - - with ThreadPoolExecutor(max_workers=2) as executor: - futures = [ - executor.submit(attempt, adapter, receipt) - for adapter, receipt in zip(adapters, receipts, strict=True) - ] - barrier.wait() - outcomes = [future.result() for future in futures] - - assert sorted(outcomes) == ["accepted", "rejected"] - restarted = AppendOnlyOperationalJournal(path, now_fn=lambda: NOW) - assert restarted.healthy is True - assert len(restarted.events(kind="broker.bootstrap.recorded")) == 1 - - -def test_inherited_broker_exposure_consumes_grant_before_new_risk(tmp_path): - adapter, _ = _adapter(tmp_path) - wrapper = _signed_envelope( - max_order_risk_cents=100, - max_open_risk_cents=100, - max_correlated_risk_cents=100, - ) - adapter.accept_signed_envelope(wrapper) - adapter.record_broker_bootstrap( - inherited_exposure_receipt( - receipt_id=_hash("inherited-receipt"), - venue="dummy_kalshi", - account_hash=ACCOUNT_HASH, - observed_at=_z(NOW), - broker_snapshot_sha256=_hash("inherited-snapshot"), - total_exposure_cents=80, - open_order_count=1, - market_exposure_cents={"KXTEST-26JUL": 80}, - correlated_exposure_cents={"KXTEST": 80}, - ) - ) - - verdict = adapter.evaluate_request( - _request(wrapper, price_cents=30), - current_daily_loss_cents=0, - ) - - assert verdict.allow is False - assert verdict.rejected_by == "capital_limits" - assert "open risk" in verdict.reason - - -def test_post_bootstrap_fill_cannot_hide_behind_inherited_exposure(tmp_path): - adapter, _ = _adapter(tmp_path) - wrapper = _signed_envelope( - max_order_risk_cents=100, - max_open_risk_cents=100, - max_correlated_risk_cents=100, - ) - adapter.accept_signed_envelope(wrapper) - adapter.record_broker_bootstrap( - inherited_exposure_receipt( - receipt_id=_hash("inherited-plus-fill-receipt"), - venue="dummy_kalshi", - account_hash=ACCOUNT_HASH, - observed_at=_z(NOW), - broker_snapshot_sha256=_hash("inherited-plus-fill-snapshot"), - total_exposure_cents=80, - open_order_count=1, - market_exposure_cents={"KXTEST-26JUL": 80}, - correlated_exposure_cents={"KXTEST": 80}, - ) - ) - - verdict = adapter.reserve_request( - _request(wrapper, price_cents=20), - current_daily_loss_cents=0, - current_local_total_exposure_cents=10, - current_local_correlated_exposure_cents=10, - ) - - assert verdict.allow is False - assert verdict.rejected_by == "capital_limits" - assert "open risk" in verdict.reason - - -def test_reservation_is_crash_safe_and_idempotent(tmp_path): - adapter, journal = _adapter(tmp_path) - wrapper = _signed_envelope() - adapter.accept_signed_envelope(wrapper) - _record_flat(adapter) - request = _request(wrapper) - - first = adapter.reserve_request(request, current_daily_loss_cents=0) - assert first.allow is True - assert first.reservation_id - - reloaded_journal = AppendOnlyOperationalJournal( - journal.path, - now_fn=lambda: NOW, - ) - reloaded = CapitalEnvelopeAdapter( - journal=reloaded_journal, - trusted_public_keys={SIGNER_KEY_ID: PUBLIC_KEY}, - expected_venue="dummy_kalshi", - expected_account_hash=ACCOUNT_HASH, - lineage_resolver=LINEAGE_RESOLVER, - now_fn=lambda: NOW, - ) - second = reloaded.reserve_request(request, current_daily_loss_cents=0) - - assert second.allow is True - assert second.reservation_id == first.reservation_id - assert ( - len(reloaded_journal.events(kind="capital.reservation.created")) == 1 - ) - conflict = reloaded.reserve_request( - _request(wrapper, size=2), - current_daily_loss_cents=0, - ) - assert conflict.allow is False - assert conflict.rejected_by == "capital_idempotency" - - -def test_two_adapters_cannot_overreserve_same_capital_ceiling(tmp_path): - first_adapter, first_journal = _adapter(tmp_path) - wrapper = _signed_envelope( - max_order_risk_cents=617, - max_open_risk_cents=1_000, - max_correlated_risk_cents=1_000, - max_daily_loss_cents=2_000, - max_open_orders=5, - ) - first_adapter.accept_signed_envelope(wrapper) - _record_flat(first_adapter) - second_adapter = CapitalEnvelopeAdapter( - journal=AppendOnlyOperationalJournal( - first_journal.path, - now_fn=lambda: NOW, - ), - trusted_public_keys={SIGNER_KEY_ID: PUBLIC_KEY}, - expected_venue="dummy_kalshi", - expected_account_hash=ACCOUNT_HASH, - lineage_resolver=LINEAGE_RESOLVER, - now_fn=lambda: NOW, - ) - first_request = _request( - wrapper, - proposal_id="concurrent-proposal-a", - price_cents=60, - size=10, - ) - second_request = _request( - wrapper, - proposal_id="concurrent-proposal-b", - price_cents=60, - size=10, - ) - barrier = threading.Barrier(2) - first_verdict = first_adapter._verdict - second_verdict = second_adapter._verdict - - def gated_first(*args, **kwargs): - result = first_verdict(*args, **kwargs) - barrier.wait(timeout=5) - return result - - def gated_second(*args, **kwargs): - result = second_verdict(*args, **kwargs) - barrier.wait(timeout=5) - return result - - first_adapter._verdict = gated_first - second_adapter._verdict = gated_second - with ThreadPoolExecutor(max_workers=2) as executor: - futures = [ - executor.submit( - first_adapter.reserve_request, - first_request, - current_daily_loss_cents=0, - ), - executor.submit( - second_adapter.reserve_request, - second_request, - current_daily_loss_cents=0, - ), - ] - verdicts = [future.result() for future in futures] - - assert sorted(verdict.allow for verdict in verdicts) == [False, True] - restarted = AppendOnlyOperationalJournal( - first_journal.path, - now_fn=lambda: NOW, - ) - reservations = restarted.events(kind="capital.reservation.created") - assert restarted.healthy is True - assert len(reservations) == 1 - assert sum(int(row["payload"]["risk_cents"]) for row in reservations) == 617 - - -def test_cross_process_dispatch_claim_is_one_shot(tmp_path): - adapter, journal = _adapter(tmp_path) - wrapper = _signed_envelope() - adapter.accept_signed_envelope(wrapper) - _record_flat(adapter) - request = _request(wrapper) - reservation = adapter.reserve_request( - request, - current_daily_loss_cents=0, - ) - assert reservation.reservation_id - order = { - "ticker": request.contract_ticker, - "client_order_id": request.proposal_id, - "side": "bid", - "count": "1.00", - "price": "0.5000", - "time_in_force": "good_till_canceled", - "self_trade_prevention_type": "taker_at_cross", - "post_only": True, - "cancel_order_on_pause": True, - "reduce_only": False, - "subaccount": 0, - "exchange_index": 0, - "expiration_time": request.expiration_ts, - } - second_journal = AppendOnlyOperationalJournal( - journal.path, - now_fn=lambda: NOW, - ) - second_adapter = CapitalEnvelopeAdapter( - journal=second_journal, - trusted_public_keys={SIGNER_KEY_ID: PUBLIC_KEY}, - expected_venue="dummy_kalshi", - expected_account_hash=ACCOUNT_HASH, - lineage_resolver=LINEAGE_RESOLVER, - now_fn=lambda: NOW, - ) - barrier = threading.Barrier(2) - - def claim( - candidate: CapitalEnvelopeAdapter, - nonce: str, - ): - barrier.wait(timeout=5) - try: - return candidate.claim_broker_dispatch( - request, - reservation_id=reservation.reservation_id, - order=order, - claimant_nonce=nonce, - ) - except (ValueError, OperationalJournalError) as exc: - return exc - - with ThreadPoolExecutor(max_workers=2) as executor: - results = [ - future.result() - for future in ( - executor.submit(claim, adapter, "1" * 64), - executor.submit(claim, second_adapter, "2" * 64), - ) - ] - - successes = [ - result - for result in results - if isinstance(result, dict) - ] - failures = [ - result - for result in results - if isinstance(result, (ValueError, OperationalJournalError)) - ] - assert len(successes) == 1 - assert successes[0]["kind"] == "capital.dispatch.claimed" - assert len(failures) == 1 - assert "already" in str(failures[0]) or "claimed" in str(failures[0]) - assert len( - second_journal.events(kind="capital.dispatch.claimed") - ) == 1 - assert len(journal.events(kind="capital.dispatch.claimed")) == 1 - with pytest.raises(ValueError, match="disabled pending sealed CAS proof"): - adapter.release_after_local_reservation_failure( - request, - reservation_id=reservation.reservation_id, - reason="caller claims transport did not occur", - ) - assert not journal.events(kind="capital.reservation.released") - - -def test_dispatch_claim_rejects_payload_drift_and_cancel_only(tmp_path): - adapter, journal = _adapter(tmp_path) - wrapper = _signed_envelope() - adapter.accept_signed_envelope(wrapper) - _record_flat(adapter) - request = _request(wrapper) - reservation = adapter.reserve_request( - request, - current_daily_loss_cents=0, - ) - assert reservation.reservation_id - order = { - "ticker": request.contract_ticker, - "client_order_id": request.proposal_id, - "side": "bid", - "count": "1.00", - "price": "0.5100", - "time_in_force": "good_till_canceled", - "self_trade_prevention_type": "taker_at_cross", - "post_only": True, - "cancel_order_on_pause": True, - "reduce_only": False, - "subaccount": 0, - "exchange_index": 0, - "expiration_time": request.expiration_ts, - } - with pytest.raises(ValueError, match="exact authorized wire payload"): - adapter.claim_broker_dispatch( - request, - reservation_id=reservation.reservation_id, - order=order, - claimant_nonce="3" * 64, - ) - - order["price"] = "0.5000" - adapter.enter_cancel_only( - reason="operator kill", - kill_asserted_at=_z(NOW), - ) - with pytest.raises(ValueError, match="cancel-only"): - adapter.claim_broker_dispatch( - request, - reservation_id=reservation.reservation_id, - order=order, - claimant_nonce="4" * 64, - ) - assert len(journal.events(kind="capital.dispatch.claimed")) == 0 - - -def test_existing_reservation_rechecks_new_broker_exposure(tmp_path): - adapter, _journal = _adapter(tmp_path) - wrapper = _signed_envelope() - adapter.accept_signed_envelope(wrapper) - _record_flat(adapter) - request = _request(wrapper) - reservation = adapter.reserve_request( - request, - current_daily_loss_cents=0, - ) - assert reservation.allow is True - adapter.record_broker_bootstrap( - inherited_exposure_receipt( - receipt_id=_hash("new-inherited-receipt"), - venue="dummy_kalshi", - account_hash=ACCOUNT_HASH, - observed_at=_z(NOW + timedelta(seconds=1)), - broker_snapshot_sha256=_hash("new-inherited-snapshot"), - total_exposure_cents=980, - open_order_count=1, - market_exposure_cents={request.market_ticker: 980}, - correlated_exposure_cents={"KXTEST": 980}, - ) - ) - - verdict = adapter.evaluate_request( - request, - current_daily_loss_cents=0, - current_local_total_exposure_cents=52, - current_local_correlated_exposure_cents=52, - current_local_open_orders=1, - current_request_locally_reserved=True, - ) - - assert verdict.allow is False - assert verdict.rejected_by == "capital_limits" - assert verdict.reason == "DumbMoney maximum open risk exceeded" - - -@pytest.mark.asyncio -async def test_local_exposure_failure_retains_capital_without_broker_contact( - tmp_path, -): - adapter, journal = _adapter(tmp_path) - wrapper = _signed_envelope() - adapter.accept_signed_envelope(wrapper) - _record_flat(adapter) - request = _request(wrapper) - tracker = ExposureTracker() - tracker.reserve_order_submission = Mock(return_value=False) - client = SimpleNamespace(create_order=AsyncMock()) - firewall = LiveBrokerFirewall( - client, - tracker, - capital_envelope_adapter=adapter, - ) - allow = FirewallVerdict(allow=True, reason="fixture") - firewall.evaluate = AsyncMock(return_value=allow) - firewall._mandatory_submit_authority = Mock(return_value=allow) - firewall._verified_live_compliance_verdict = AsyncMock(return_value=allow) - firewall._trusted_sink_orderbook = AsyncMock( - return_value=(SimpleNamespace(), allow) - ) - - result = await firewall.submit(request, SimpleNamespace(), None) - - assert result.success is False - assert result.error == "EXPOSURE_RESERVATION_FAILED" - assert result.broker_contacted is False - client.create_order.assert_not_awaited() - releases = journal.events(kind="capital.reservation.released") - assert len(journal.events(kind="capital.reservation.created")) == 1 - assert not journal.events(kind="capital.local_reservation.failed") - assert releases == () - reused = adapter.evaluate_request( - request, - current_daily_loss_cents=0, - ) - assert reused.allow is True - assert reused.reservation_id is not None - - -@pytest.mark.asyncio -async def test_authority_loss_after_reservation_never_contacts_broker( - tmp_path, -): - adapter, journal = _adapter(tmp_path) - wrapper = _signed_envelope() - adapter.accept_signed_envelope(wrapper) - _record_flat(adapter) - request = _request(wrapper) - tracker = ExposureTracker() - client = SimpleNamespace(create_order=AsyncMock()) - firewall = LiveBrokerFirewall( - client, - tracker, - capital_envelope_adapter=adapter, - ) - allow = FirewallVerdict(allow=True, reason="fixture") - revoked = FirewallVerdict( - allow=False, - reason="Kill switch active", - rejected_by="kill_switch", - ) - firewall.evaluate = AsyncMock(return_value=allow) - firewall._mandatory_submit_authority = Mock( - side_effect=[allow, allow, revoked] - ) - firewall._verified_live_compliance_verdict = AsyncMock( - return_value=allow - ) - firewall._trusted_sink_orderbook = AsyncMock( - return_value=(SimpleNamespace(), allow) - ) - - result = await firewall.submit(request, SimpleNamespace(), None) - - assert result.success is False - assert result.error == "Kill switch active" - assert result.broker_contacted is False - client.create_order.assert_not_awaited() - assert len(journal.events(kind="capital.reservation.created")) == 1 - assert journal.events(kind="capital.reservation.released") == () - assert tracker.open_order_count() == 1 - - -@pytest.mark.asyncio -async def test_authority_loss_after_dispatch_claim_never_contacts_broker( - tmp_path, -): - adapter, journal = _adapter(tmp_path) - wrapper = _signed_envelope() - adapter.accept_signed_envelope(wrapper) - _record_flat(adapter) - request = _request(wrapper) - tracker = ExposureTracker() - client = SimpleNamespace(create_order=AsyncMock()) - firewall = LiveBrokerFirewall( - client, - tracker, - capital_envelope_adapter=adapter, - ) - allow = FirewallVerdict(allow=True, reason="fixture") - revoked = FirewallVerdict( - allow=False, - reason="Core command authority expired", - rejected_by="core_command_authority", - ) - firewall.evaluate = AsyncMock(return_value=allow) - firewall._mandatory_submit_authority = Mock( - side_effect=[allow, allow, allow, revoked] - ) - firewall._verified_live_compliance_verdict = AsyncMock( - return_value=allow - ) - firewall._trusted_sink_orderbook = AsyncMock( - return_value=(SimpleNamespace(), allow) - ) - - result = await firewall.submit(request, SimpleNamespace(), None) - - assert result.success is False - assert result.error == "Core command authority expired" - assert result.broker_contacted is False - client.create_order.assert_not_awaited() - assert len(journal.events(kind="capital.dispatch.claimed")) == 1 - assert len(journal.events(kind="capital.reservation.created")) == 1 - assert journal.events(kind="capital.reservation.released") == () - assert tracker.open_order_count() == 1 - - -@pytest.mark.asyncio -async def test_existing_ambiguous_submission_is_reconciliation_only( - tmp_path, -): - adapter, journal = _adapter(tmp_path) - wrapper = _signed_envelope() - adapter.accept_signed_envelope(wrapper) - _record_flat(adapter) - request = _request(wrapper) - capital = adapter.reserve_request(request, current_daily_loss_cents=0) - assert capital.allow is True - tracker = ExposureTracker() - assert tracker.reserve_order_submission( - request.proposal_id, - request.market_ticker, - request.size, - request.price_cents, - contract_ticker=request.contract_ticker, - side=request.side, - ) - client = SimpleNamespace(create_order=AsyncMock()) - firewall = LiveBrokerFirewall( - client, - tracker, - capital_envelope_adapter=adapter, - ) - allow = FirewallVerdict(allow=True, reason="fixture") - firewall.evaluate = AsyncMock(return_value=allow) - firewall._mandatory_submit_authority = Mock(return_value=allow) - firewall._verified_live_compliance_verdict = AsyncMock( - return_value=allow - ) - firewall._trusted_sink_orderbook = AsyncMock( - return_value=(SimpleNamespace(), allow) - ) - - result = await firewall.submit(request, SimpleNamespace(), None) - - assert result.success is False - assert ( - result.error - == "EXISTING_SUBMISSION_REQUIRES_BROKER_RECONCILIATION" - ) - assert result.broker_contacted is False - client.create_order.assert_not_awaited() - assert journal.events(kind="capital.reservation.released") == () - assert tracker.submission_record(request.proposal_id) is not None - assert tracker.state_healthy is True - - -def test_fee_inclusive_reservation_records_notional_and_worst_case_fee( - tmp_path, -): - adapter, journal = _adapter(tmp_path) - wrapper = _signed_envelope() - adapter.accept_signed_envelope(wrapper) - _record_flat(adapter) - - verdict = adapter.reserve_request( - _request(wrapper, price_cents=50, size=2), - current_daily_loss_cents=0, - ) - - assert verdict.allow is True - payload = journal.events( - kind="capital.reservation.created" - )[0]["payload"] - assert payload["notional_cents"] == 100 - assert payload["fee_reserve_cents"] == 4 - assert payload["risk_cents"] == 104 - - -def test_signed_terminal_and_settlement_witnesses_release_in_order( - tmp_path, -): - adapter, journal = _adapter(tmp_path) - wrapper = _signed_envelope( - max_order_risk_cents=100, - max_open_risk_cents=100, - max_correlated_risk_cents=100, - ) - adapter.accept_signed_envelope(wrapper) - _record_flat(adapter) - request = _request(wrapper) - reservation = adapter.reserve_request( - request, - current_daily_loss_cents=0, - ) - assert reservation.reservation_id is not None - adapter.claim_broker_dispatch( - request, - reservation_id=reservation.reservation_id, - order=adapter._expected_broker_order(request), - claimant_nonce="9" * 64, - ) - pending = adapter.pending_reconciliation_reservations() - assert len(pending) == 1 - terminal_wrapper = _terminal_witness(pending[0]) - tracker = ExposureTracker( - persist=True, - state_path=tmp_path / "live-exposure.json", - ) - assert tracker.reserve_order_submission( - request.proposal_id, - request.market_ticker, - request.size, - request.price_cents, - contract_ticker=request.contract_ticker, - side=request.side, - ) - assert tracker.confirm_open_order( - request.proposal_id, - "broker-order-1", - ) - - class Reader: - settlement: dict | None = None - - def terminal_reconciliation_witness(self, _reservation): - return terminal_wrapper - - def settlement_reconciliation_witness(self, _position): - return self.settlement - - reader = Reader() - sweeper = DumbMoneyKalshiReconciliationSweeper( - capital_adapter=adapter, - broker_reader=reader, - exposure_tracker=tracker, - ) - - first = sweeper.run_once() - - assert first["status"] == "BLOCKED" - assert first["terminal_witnesses_recorded"] == 1 - assert first["unresolved_positions"] == 1 - assert adapter.pending_reconciliation_reservations() == () - positions = adapter.active_position_exposures() - assert len(positions) == 1 - assert positions[0]["risk_cents"] == 52 - assert tracker.open_order_count() == 0 - assert tracker.positions[ - (request.contract_ticker, request.side) - ].quantity == 1 - blocked = adapter.evaluate_request( - _request(wrapper, proposal_id="proposal-after-fill"), - current_daily_loss_cents=0, - ) - assert blocked.allow is False - assert blocked.reason == "DumbMoney maximum open risk exceeded" - - reader.settlement = _settlement_witness(positions[0]) - second = sweeper.run_once() - - assert second["status"] == "COMPLETE" - assert second["settlement_witnesses_recorded"] == 1 - assert adapter.active_position_exposures() == () - assert tracker.positions == {} - allowed = adapter.evaluate_request( - _request(wrapper, proposal_id="proposal-after-settlement"), - current_daily_loss_cents=0, - ) - assert allowed.allow is True - assert len( - journal.events( - kind="capital.terminal_reconciliation.witnessed" - ) - ) == 1 - assert len( - journal.events( - kind="capital.settlement_reconciliation.witnessed" - ) - ) == 1 - - # A restart sees no pending authority and does not duplicate releases. - restarted_journal = AppendOnlyOperationalJournal( - journal.path, - now_fn=lambda: NOW, - ) - restarted = CapitalEnvelopeAdapter( - journal=restarted_journal, - trusted_public_keys={SIGNER_KEY_ID: PUBLIC_KEY}, - trusted_broker_witness_public_keys={ - WITNESS_KEY_ID: WITNESS_PUBLIC_KEY - }, - expected_venue="dummy_kalshi", - expected_account_hash=ACCOUNT_HASH, - lineage_resolver=LINEAGE_RESOLVER, - now_fn=lambda: NOW, - ) - assert restarted.pending_reconciliation_reservations() == () - assert restarted.active_position_exposures() == () - - -def test_terminal_witness_tamper_or_wrong_signer_never_releases( - tmp_path, -): - adapter, journal = _adapter(tmp_path) - wrapper = _signed_envelope() - adapter.accept_signed_envelope(wrapper) - _record_flat(adapter) - request = _request(wrapper) - reservation = adapter.reserve_request( - request, - current_daily_loss_cents=0, - ) - assert reservation.reservation_id is not None - adapter.claim_broker_dispatch( - request, - reservation_id=reservation.reservation_id, - order=adapter._expected_broker_order(request), - claimant_nonce="8" * 64, - ) - terminal = _terminal_witness( - adapter.pending_reconciliation_reservations()[0] - ) - tampered = copy.deepcopy(terminal) - tampered["body"]["fill_cost_cents"] += 1 - - with pytest.raises(ValueError, match="digest"): - adapter.record_signed_terminal_reconciliation(tampered) - - wrong_key = Ed25519PrivateKey.from_private_bytes(bytes([7]) * 32) - wrong = sign_broker_witness( - terminal["body"], - private_key=wrong_key, - observed_at=NOW, - correlation_id=request.proposal_id, - ) - with pytest.raises(ValueError, match="trusted"): - adapter.record_signed_terminal_reconciliation(wrong) - - assert journal.events(kind="capital.reservation.released") == () - assert adapter.pending_reconciliation_reservations() - - -def test_caller_authored_terminal_receipts_never_release_capital(tmp_path): - adapter, journal = _adapter(tmp_path) - wrapper = _signed_envelope( - max_order_risk_cents=100, - max_open_risk_cents=100, - max_correlated_risk_cents=100, - ) - adapter.accept_signed_envelope(wrapper) - _record_flat(adapter) - request = _request(wrapper, price_cents=80) - reservation = adapter.reserve_request( - request, - current_daily_loss_cents=0, - ) - assert reservation.reservation_id - - with pytest.raises(ValueError, match="sealed broker witness"): - adapter.release_from_terminal_reconciliation( - proposal_id=request.proposal_id, - terminal_status="ambiguous", - reconciliation_receipt={ - "schema": "dummy.terminal-order-reconciliation.v1", - "terminal_status": "ambiguous", - "proposal_id": request.proposal_id, - "order_id": "broker-order-1", - "broker_contacted": True, - "local_exposure_projection_persisted": True, - }, - ) - with pytest.raises(ValueError, match="sealed broker witness"): - adapter.release_from_terminal_reconciliation( - proposal_id=request.proposal_id, - terminal_status="filled", - reconciliation_receipt={ - "schema": "dummy.terminal-order-reconciliation.v1", - "terminal_status": "filled", - "proposal_id": request.proposal_id, - "order_id": "broker-order-1", - "broker_contacted": False, - "local_exposure_projection_persisted": True, - }, - ) - assert not journal.events(kind="capital.reservation.released") - - receipt = { - "schema": "dummy.terminal-order-reconciliation.v1", - "terminal_status": "filled", - "proposal_id": request.proposal_id, - "broker_contacted": True, - "order_id": "broker-order-1", - "fill_count": 1, - "fill_price_cents": request.price_cents, - "local_exposure_projection_persisted": True, - } - with pytest.raises(ValueError, match="sealed broker witness"): - adapter.release_from_terminal_reconciliation( - proposal_id=request.proposal_id, - terminal_status="filled", - reconciliation_receipt=receipt, - ) - - reloaded_journal = AppendOnlyOperationalJournal( - journal.path, - now_fn=lambda: NOW, - ) - reloaded = CapitalEnvelopeAdapter( - journal=reloaded_journal, - trusted_public_keys={SIGNER_KEY_ID: PUBLIC_KEY}, - expected_venue="dummy_kalshi", - expected_account_hash=ACCOUNT_HASH, - lineage_resolver=LINEAGE_RESOLVER, - now_fn=lambda: NOW, - ) - with pytest.raises(ValueError, match="sealed broker witness"): - reloaded.release_from_terminal_reconciliation( - proposal_id=request.proposal_id, - terminal_status="filled", - reconciliation_receipt=receipt, - ) - assert not reloaded_journal.events( - kind="capital.terminal_reconciliation.witnessed" - ) - assert not reloaded_journal.events(kind="capital.reservation.released") - assert not reloaded_journal.events(kind="capital.position.exposure.recorded") - replay = reloaded.reserve_request( - request, - current_daily_loss_cents=0, - ) - assert replay.allow is True - assert replay.reservation_id == reservation.reservation_id - - # Filled risk remains charged in the independent capital journal even if a - # different process has an empty or stale local position book. - next_request = _request( - wrapper, - proposal_id="proposal-2", - price_cents=30, - ) - blocked = reloaded.evaluate_request( - next_request, - current_daily_loss_cents=0, - ) - assert blocked.allow is False - assert "open risk" in blocked.reason - - -def test_brain_releases_only_after_persisted_terminal_broker_witness( - tmp_path, - monkeypatch, -): - import live_firewall.exposure_tracker as tracker_module - - adapter, journal = _adapter(tmp_path) - wrapper = _signed_envelope() - adapter.accept_signed_envelope(wrapper) - _record_flat(adapter) - request = _request(wrapper) - assert adapter.reserve_request( - request, - current_daily_loss_cents=0, - ).allow - tracker = ExposureTracker() - assert tracker.reserve_order_submission( - request.proposal_id, - request.market_ticker, - request.size, - request.price_cents, - contract_ticker=request.contract_ticker, - side=request.side, - ) - assert tracker.confirm_open_order(request.proposal_id, "broker-order-1") - monkeypatch.setattr( - tracker_module, - "get_persistent_exposure_tracker", - lambda: tracker, - ) - brain = SimpleNamespace( - mode=SessionMode.LIVE, - executor=SimpleNamespace(capital_envelope_adapter=adapter), - ) - outcome = TradeOutcome( - decision_id="test-decision", - market_ticker=request.market_ticker, - kind=OutcomeKind.FILLED, - order_id="broker-order-1", - fill_count=1, - fill_price_cents=request.price_cents, - pnl_cents=None, - broker_contacted=True, - detail={"state": "filled"}, - created_at=_z(NOW), - ) - - PredatorBrain._sync_live_exposure(brain, [outcome]) - - assert not journal.events(kind="capital.reservation.released") - assert not journal.events(kind="capital.position.exposure.recorded") - assert tracker.open_order_count() == 0 - assert tracker.total_exposure_cents() == request.price_cents - - -def test_brain_retains_capital_without_terminal_status_witness( - tmp_path, - monkeypatch, -): - import live_firewall.exposure_tracker as tracker_module - - adapter, journal = _adapter(tmp_path) - wrapper = _signed_envelope() - adapter.accept_signed_envelope(wrapper) - _record_flat(adapter) - request = _request(wrapper) - assert adapter.reserve_request( - request, - current_daily_loss_cents=0, - ).allow - tracker = ExposureTracker() - assert tracker.reserve_order_submission( - request.proposal_id, - request.market_ticker, - request.size, - request.price_cents, - contract_ticker=request.contract_ticker, - side=request.side, - ) - assert tracker.confirm_open_order(request.proposal_id, "broker-order-1") - monkeypatch.setattr( - tracker_module, - "get_persistent_exposure_tracker", - lambda: tracker, - ) - brain = SimpleNamespace( - mode=SessionMode.LIVE, - executor=SimpleNamespace(capital_envelope_adapter=adapter), - ) - ambiguous_cancel = TradeOutcome( - decision_id="test-decision", - market_ticker=request.market_ticker, - kind=OutcomeKind.CANCELED, - order_id="broker-order-1", - fill_count=0, - fill_price_cents=request.price_cents, - pnl_cents=None, - broker_contacted=True, - detail={"reason": "cancel_requested_without_terminal_status"}, - created_at=_z(NOW), - ) - - PredatorBrain._sync_live_exposure(brain, [ambiguous_cancel]) - - assert not journal.events(kind="capital.reservation.released") - - -def test_cancel_only_degraded_mode_never_invents_cancel_authority(tmp_path): - adapter, journal = _adapter(tmp_path) - wrapper = _signed_envelope() - adapter.accept_signed_envelope(wrapper) - _record_flat(adapter) - request = _request(wrapper) - assert adapter.evaluate_request(request, current_daily_loss_cents=0).allow - - receipt = adapter.enter_cancel_only( - reason="kill switch asserted", - kill_asserted_at=_z(NOW), - ) - - assert receipt["payload"]["submission_authority"] is False - assert receipt["payload"]["cancel_authority"] is False - assert receipt["payload"]["broker_contacted"] is False - assert not journal.events(kind="cancel.reconciliation.requested") - blocked = adapter.evaluate_request(request, current_daily_loss_cents=0) - assert blocked.allow is False - assert blocked.rejected_by == "capital_cancel_only" - - with pytest.raises(ValueError, match="opaque receipt"): - adapter.enter_cancel_only( - reason="unverified cancel authority supplied", - kill_asserted_at=_z(NOW), - cancel_authorized=True, - cancel_authority_receipt="opaque-authority-claim", - ) - assert not journal.events(kind="cancel.reconciliation.requested") - - -def test_kill_queue_mirrors_cancel_only_without_cancel_command(tmp_path): - adapter, journal = _adapter(tmp_path) - - receipt = queue_kill_reconciliation( - kill_asserted_at=_z(NOW), - receipt_path=tmp_path / "kill-reconciliation.json", - capital_envelope_adapter=adapter, - ) - - assert receipt["submission_authority"] is False - assert receipt["cancel_authority"] is False - assert receipt["broker_contacted"] is False - assert receipt["dumbmoney_operational_status"] == "CANCEL_AUTHORITY_REQUIRED" - assert len(journal.events(kind="authority.cancel_only")) == 1 - assert not journal.events(kind="cancel.reconciliation.requested") - - -@pytest.mark.asyncio -@pytest.mark.parametrize( - ("local_order_cap", "grant_order_cap", "expected_rejected_by"), - [ - (100, 500, "single_order_cap"), - (500, 100, "capital_limits"), - ], -) -async def test_firewall_intersects_local_and_signed_caps( - tmp_path, - monkeypatch, - local_order_cap, - grant_order_cap, - expected_rejected_by, -): - import live_firewall.firewall as firewall_module - - adapter, _ = _adapter(tmp_path) - wrapper = _signed_envelope( - max_order_risk_cents=grant_order_cap, - max_open_risk_cents=1_000, - max_correlated_risk_cents=1_000, - ) - adapter.accept_signed_envelope(wrapper) - _record_flat(adapter) - request = _request(wrapper, price_cents=50, size=3) - caps = CapConfig( - max_single_order_cents=local_order_cap, - max_market_exposure_cents=2_000, - max_correlated_exposure_cents=2_000, - max_total_live_exposure_cents=2_000, - max_daily_loss_cents=1_000, - max_open_markets=10, - max_orders_per_hour=10, - allowed_markets=[request.market_ticker], - max_spread_cents=5, - min_liquidity=10, - min_edge_bps=50, - ) - monkeypatch.setattr(firewall_module, "load_caps", lambda: caps) - monkeypatch.setattr( - firewall_module, - "get_allowed_adapter_names", - lambda: {"kalshi_live_firewall_adapter"}, - ) - monkeypatch.setenv("KALSHI_API_KEY_ID", "fixture-key-id") - state = DummyState() - state.set_mode(AccountMode.AUTONOMOUS_LIVE_CAPPED) - monkeypatch.setattr(firewall_module, "STATE", state) - firewall = LiveBrokerFirewall( - None, - ExposureTracker(), - capital_envelope_adapter=adapter, - ) - book = OrderBook( - market_ticker=request.market_ticker, - contract_ticker=request.contract_ticker, - bids=[OrderBookLevel(price=48, size=20)], - asks=[OrderBookLevel(price=52, size=20)], - timestamp=datetime.now(timezone.utc), - ) - forecast = Forecast( - market_ticker=request.market_ticker, - contract_ticker=request.contract_ticker, - event_title="Fixture", - contract_title="Fixture yes", - market_implied_probability=Decimal("0.50"), - dummy_probability=Decimal("0.80"), - probability_delta=Decimal("0.30"), - confidence_score=Decimal("0.80"), - uncertainty_band=(Decimal("0.75"), Decimal("0.85")), - expected_edge=Decimal("0.25"), - edge_after_fees=Decimal("0.20"), - freshness_score=Decimal("1"), - liquidity_score=Decimal("1"), - spread_score=Decimal("1"), - orderbook_depth_score=Decimal("1"), - settlement_risk_score=Decimal("0.1"), - source_summary="fixture", - model_summary="fixture", - calibration_notes="fixture", - timestamp=datetime.now(timezone.utc), - expiration=datetime.now(timezone.utc) + timedelta(hours=1), - strategy_references=[STRATEGY_REFERENCE], - proof_reference=PASSPORT_REFERENCE, - ) - - verdict = await firewall.evaluate(request, book, forecast) - - assert verdict.allow is False - assert verdict.rejected_by == expected_rejected_by - - -def test_final_firewall_authority_requires_current_core_command_state( - tmp_path, -): - adapter, _ = _adapter(tmp_path) - wrapper = _signed_envelope() - adapter.accept_signed_envelope(wrapper) - _record_flat(adapter) - request = _request(wrapper) - firewall = LiveBrokerFirewall( - None, - ExposureTracker(), - capital_envelope_adapter=adapter, - core_submission_authority=lambda: False, - ) - - verdict = firewall._mandatory_submit_authority(request) - - assert verdict.allow is False - assert verdict.rejected_by == "core_command_authority" - - -def test_operational_journal_outbox_is_append_only_and_replayable(tmp_path): - path = tmp_path / "journal.jsonl" - journal = AppendOnlyOperationalJournal(path, now_fn=lambda: NOW) - first = journal.append( - "fixture.event", - {"value": 1}, - outbox_id="fixture-outbox", - ) - repeated = journal.append( - "fixture.event", - {"value": 1}, - outbox_id="fixture-outbox", - ) - assert repeated["event_sha256"] == first["event_sha256"] - assert len(journal.pending_outbox()) == 1 - - journal.acknowledge_outbox( - "fixture-outbox", - acknowledgement={"receiver": "dumbmoney-core"}, - ) - assert journal.pending_outbox() == () - - reloaded = AppendOnlyOperationalJournal(path, now_fn=lambda: NOW) - assert reloaded.healthy is True - assert len(reloaded.events()) == 2 - - -def test_operational_journal_serializes_two_preloaded_instances(tmp_path): - path = tmp_path / "shared-journal.jsonl" - first_writer = AppendOnlyOperationalJournal(path, now_fn=lambda: NOW) - second_writer = AppendOnlyOperationalJournal(path, now_fn=lambda: NOW) - - first = first_writer.append("writer.a", {"value": 1}) - second = second_writer.append("writer.b", {"value": 2}) - third = first_writer.append("writer.a", {"value": 3}) - - assert [first["sequence"], second["sequence"], third["sequence"]] == [1, 2, 3] - assert second["previous_sha256"] == first["event_sha256"] - assert third["previous_sha256"] == second["event_sha256"] - assert [row["kind"] for row in second_writer.events()] == [ - "writer.a", - "writer.b", - "writer.a", - ] - - restarted = AppendOnlyOperationalJournal(path, now_fn=lambda: NOW) - assert restarted.healthy is True - assert [row["sequence"] for row in restarted.events()] == [1, 2, 3] diff --git a/tests/test_dumbmoney_command_feed.py b/tests/test_dumbmoney_command_feed.py deleted file mode 100644 index 2638015a..00000000 --- a/tests/test_dumbmoney_command_feed.py +++ /dev/null @@ -1,1163 +0,0 @@ -from __future__ import annotations - -import base64 -import copy -import hashlib -import json -from concurrent.futures import ThreadPoolExecutor -from datetime import datetime, timedelta, timezone -from pathlib import Path - -import pytest -from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey - -from live_firewall.dumbmoney_capital import ( - CAPITAL_ENVELOPE_SCHEMA, - SIGNED_ENVELOPE_SCHEMA, - CapitalEnvelopeAdapter, -) -from live_firewall.dumbmoney_command_feed import ( - DESIRED_MODE_SCHEMA, - KILL_STATE_SCHEMA, - CommandFeedResponse, - CoreCommandFeedConsumer, - ZERO_DIGEST, -) -from live_firewall.operational_journal import ( - AppendOnlyOperationalJournal, - canonical_json, - sha256_json, -) - - -NOW = datetime(2026, 7, 26, 21, 0, 0, tzinfo=timezone.utc) -CORE_PRIVATE_KEY = Ed25519PrivateKey.from_private_bytes(bytes(range(32))) -CORE_PUBLIC_KEY = CORE_PRIVATE_KEY.public_key().public_bytes_raw() -CORE_SIGNER_KEY_ID = hashlib.sha256(CORE_PUBLIC_KEY).hexdigest() -OPERATOR_PRIVATE_KEY = Ed25519PrivateKey.from_private_bytes( - bytes(range(1, 33)) -) -OPERATOR_PUBLIC_KEY = OPERATOR_PRIVATE_KEY.public_key().public_bytes_raw() -OPERATOR_SIGNER_KEY_ID = hashlib.sha256(OPERATOR_PUBLIC_KEY).hexdigest() -ACCOUNT_HASH = hashlib.sha256(b"dummy-command-feed-account").hexdigest() -STRATEGY_HASH = hashlib.sha256(b"strategy").hexdigest() -PASSPORT_HASH = hashlib.sha256(b"passport").hexdigest() -PROMOTION_HASH = hashlib.sha256(b"promotion").hexdigest() -INSTRUMENT = "event_contract:KXTEST-26JUL" -REQUEST_NONCE_1 = "1" * 64 -REQUEST_NONCE_2 = "2" * 64 -REQUEST_NONCE_3 = "3" * 64 - - -class _UnusedLineageResolver: - def resolve_lineage(self, **_kwargs): - raise AssertionError("command-feed tests must not resolve live lineage") - - -def _hash(label: str) -> str: - return hashlib.sha256(label.encode("utf-8")).hexdigest() - - -def _z(value: datetime) -> str: - return value.astimezone(timezone.utc).isoformat().replace("+00:00", "Z") - - -def _sign( - body: dict, - *, - source_sequence: int, - not_before: datetime, - expires_at: datetime, - signer_role: str | None = None, -) -> dict: - role = signer_role or ( - "core" if body["schema"] == CAPITAL_ENVELOPE_SCHEMA else "operator" - ) - if role == "core": - private_key = CORE_PRIVATE_KEY - signer_key_id = CORE_SIGNER_KEY_ID - elif role == "operator": - private_key = OPERATOR_PRIVATE_KEY - signer_key_id = OPERATOR_SIGNER_KEY_ID - else: - raise ValueError(f"unsupported signer role: {role}") - identity = { - "schema": SIGNED_ENVELOPE_SCHEMA, - "source_id": "dumbmoney-control", - "source_sequence": source_sequence, - "correlation_id": "dummy-command-feed-test", - "causation_id": None, - "nonce": f"command-nonce-{source_sequence}", - "not_before": _z(not_before), - "expires_at": _z(expires_at), - "body_schema": body["schema"], - "body_digest": sha256_json(body), - "body": body, - "signature_algorithm": "Ed25519", - "signer_key_id": signer_key_id, - } - wrapper = {**identity, "event_id": sha256_json(identity)} - wrapper["signature"] = ( - base64.urlsafe_b64encode( - private_key.sign(canonical_json(wrapper).encode("utf-8")) - ) - .decode("ascii") - .rstrip("=") - ) - return wrapper - - -def _kill( - *, - sequence: int, - active: bool, - generation: int, - not_before: datetime = NOW - timedelta(seconds=10), - expires_at: datetime = NOW + timedelta(minutes=5), - signer_role: str | None = None, -) -> dict: - body = { - "schema": KILL_STATE_SCHEMA, - "active": active, - "generation": generation, - "reason": "test kill state", - "changed_by": "test-operator", - "policy_epoch": 1, - "changed_at": _z(min(NOW, expires_at - timedelta(seconds=1))), - } - return _sign( - body, - source_sequence=sequence, - not_before=not_before, - expires_at=expires_at, - signer_role=signer_role, - ) - - -def _mode( - *, - sequence: int, - mode: str, - revision: int, - not_before: datetime = NOW - timedelta(seconds=10), - expires_at: datetime = NOW + timedelta(minutes=5), - signer_role: str | None = None, -) -> dict: - body = { - "schema": DESIRED_MODE_SCHEMA, - "venue": "dummy_kalshi", - "mode": mode, - "revision": revision, - "reason": "test desired mode", - "policy_epoch": 1, - "not_before": _z(not_before), - "expires_at": _z(expires_at), - } - return _sign( - body, - source_sequence=sequence, - not_before=not_before, - expires_at=expires_at, - signer_role=signer_role, - ) - - -def _capital( - *, - sequence: int, - fence: int = 1, - not_before: datetime = NOW - timedelta(seconds=10), - expires_at: datetime = NOW + timedelta(seconds=50), - signer_role: str | None = None, -) -> dict: - body = { - "schema": CAPITAL_ENVELOPE_SCHEMA, - "envelope_id": _hash(f"capital-envelope:{sequence}"), - "mandate_id": _hash("mandate"), - "venue": "dummy_kalshi", - "account_hash": ACCOUNT_HASH, - "strategy_hashes": [STRATEGY_HASH], - "passport_hashes": [PASSPORT_HASH], - "promotion_hashes": [PROMOTION_HASH], - "authorized_instruments": [INSTRUMENT], - "authorized_mode": "LIVE", - "max_order_risk_cents": 100, - "max_open_risk_cents": 500, - "max_correlated_risk_cents": 300, - "max_daily_loss_cents": 200, - "max_open_orders": 3, - "fencing_generation": fence, - "policy_epoch": 1, - "not_before": _z(not_before), - "expires_at": _z(expires_at), - } - return _sign( - body, - source_sequence=sequence, - not_before=not_before, - expires_at=expires_at, - signer_role=signer_role, - ) - - -def _command( - envelope: dict, - *, - global_sequence: int, -) -> dict: - return { - "global_sequence": global_sequence, - "event_id": envelope["event_id"], - "event_digest": ZERO_DIGEST, - "body_schema": envelope["body_schema"], - "valid_now": False, - "transport_window_current": False, - "authority_effect": "HISTORICAL_ONLY", - "ledger_proof": {}, - "envelope": envelope, - } - - -def _parse_z(value: str) -> datetime: - return datetime.fromisoformat(value[:-1] + "+00:00") - - -def _decorate_commands( - commands: list[dict], - *, - after_sequence: int, - after_digest: str, - observed_at: datetime, -) -> None: - previous_command: dict | None = None - source_heads: dict[str, dict] = {} - for command in commands: - envelope = command["envelope"] - body = envelope["body"] - wrapper_not_before = _parse_z(envelope["not_before"]) - wrapper_expires_at = _parse_z(envelope["expires_at"]) - transport_current = ( - wrapper_not_before <= observed_at < wrapper_expires_at - ) - if envelope["body_schema"] == KILL_STATE_SCHEMA: - body_current = ( - _parse_z(body["changed_at"]) - <= observed_at + timedelta(seconds=5) - ) - positive_grant = body["active"] is False - elif envelope["body_schema"] in { - DESIRED_MODE_SCHEMA, - CAPITAL_ENVELOPE_SCHEMA, - }: - body_current = ( - _parse_z(body["not_before"]) - <= observed_at - < _parse_z(body["expires_at"]) - ) - positive_grant = ( - envelope["body_schema"] == CAPITAL_ENVELOPE_SCHEMA - or body["mode"] == "LIVE" - ) - else: - body_current = transport_current - positive_grant = True - valid_now = transport_current and body_current - command["transport_window_current"] = transport_current - command["valid_now"] = valid_now - command["authority_effect"] = ( - "APPLY_FAIL_CLOSED" - if not positive_grant - else "APPLY_POSITIVE" - if valid_now - else "HISTORICAL_ONLY" - ) - - sequence = command["global_sequence"] - if sequence == 1: - previous_global_digest = ZERO_DIGEST - elif sequence == after_sequence + 1: - previous_global_digest = after_digest - elif ( - previous_command is not None - and sequence == previous_command["global_sequence"] + 1 - ): - previous_global_digest = previous_command["event_digest"] - else: - previous_global_digest = _hash( - f"unprojected-global-event:{sequence - 1}" - ) - - source_id = envelope["source_id"] - source_sequence = envelope["source_sequence"] - prior_source = source_heads.get(source_id) - if source_sequence == 1: - previous_source_digest = ZERO_DIGEST - elif ( - prior_source is not None - and source_sequence - == prior_source["envelope"]["source_sequence"] + 1 - ): - previous_source_digest = prior_source["event_digest"] - elif sequence == after_sequence + 1: - previous_source_digest = after_digest - else: - previous_source_digest = _hash( - f"unprojected-source-event:{source_id}:{source_sequence - 1}" - ) - - received_at = observed_at - timedelta(seconds=1) - record_observed_at = max(received_at, wrapper_not_before) - event_material = { - "global_sequence": sequence, - "event_id": envelope["event_id"], - "source_id": source_id, - "source_sequence": source_sequence, - "signer_key_id": envelope["signer_key_id"], - "nonce": envelope["nonce"], - "event_schema": envelope["body_schema"], - "observed_at": _z(record_observed_at), - "received_at": _z(received_at), - "correlation_id": envelope["correlation_id"], - "causation_id": envelope["causation_id"], - "payload_digest": envelope["body_digest"], - "previous_source_digest": previous_source_digest, - "previous_global_digest": previous_global_digest, - } - event_digest = sha256_json(event_material) - command["event_digest"] = event_digest - command["ledger_proof"] = { - "schema": "dumbmoney.ledger-event-proof.v1", - **event_material, - "event_digest": event_digest, - } - source_heads[source_id] = command - previous_command = command - - -def _checkpoint_signature(checkpoint: dict) -> dict: - signature = CORE_PRIVATE_KEY.sign( - canonical_json(checkpoint).encode("utf-8") - ) - return { - "algorithm": "Ed25519", - "signer_key_id": CORE_SIGNER_KEY_ID, - "signature": ( - base64.urlsafe_b64encode(signature) - .decode("ascii") - .rstrip("=") - ), - } - - -def _page( - commands: list[dict], - *, - after_sequence: int = 0, - after_digest: str = ZERO_DIGEST, - next_sequence: int | None = None, - next_digest: str | None = None, - ledger_head_sequence: int | None = None, - ledger_head_digest: str | None = None, - required_action: str, - observed_at: datetime = NOW, - request_nonce: str = REQUEST_NONCE_1, -) -> bytes: - _decorate_commands( - commands, - after_sequence=after_sequence, - after_digest=after_digest, - observed_at=observed_at, - ) - resolved_next = ( - commands[-1]["global_sequence"] - if next_sequence is None and commands - else after_sequence - if next_sequence is None - else next_sequence - ) - if next_digest is not None: - resolved_digest = next_digest - elif commands and commands[-1]["global_sequence"] == resolved_next: - resolved_digest = commands[-1]["event_digest"] - elif resolved_next == after_sequence: - resolved_digest = after_digest - else: - resolved_digest = _hash(f"ledger-event:{resolved_next}") - head = resolved_next if ledger_head_sequence is None else ledger_head_sequence - resolved_head_digest = ( - ledger_head_digest - if ledger_head_digest is not None - else resolved_digest - if head == resolved_next - else _hash(f"ledger-head:{head}") - ) - ordered_commands = [ - { - key: copy.deepcopy(item) - for key, item in command.items() - if key != "envelope" - } - for command in commands - ] - checkpoint = { - "schema": "dumbmoney.cell-command-checkpoint.v1", - "cell_id": "dummy_kalshi", - "request_nonce": request_nonce, - "after_sequence": after_sequence, - "after_digest": after_digest, - "ordered_commands": ordered_commands, - "next_sequence": resolved_next, - "next_digest": resolved_digest, - "ledger_head_sequence": head, - "ledger_head_digest": resolved_head_digest, - "observed_at": _z(observed_at), - "required_action": required_action, - } - value = { - "schema": "dumbmoney.cell-command-page.v1", - "cell_id": "dummy_kalshi", - "request_nonce": request_nonce, - "observed_at": _z(observed_at), - "after_sequence": after_sequence, - "after_digest": after_digest, - "next_sequence": resolved_next, - "next_digest": resolved_digest, - "ledger_head_sequence": head, - "ledger_head_digest": resolved_head_digest, - "has_more": resolved_next < head, - "required_action": required_action, - "commands": commands, - "checkpoint": checkpoint, - "checkpoint_signature": _checkpoint_signature(checkpoint), - } - return canonical_json(value).encode("utf-8") - - -class _Transport: - def __init__(self, responses: list[CommandFeedResponse | Exception]): - self.responses = list(responses) - self.calls: list[tuple[str, dict[str, str]]] = [] - - def __call__(self, path: str, headers: dict[str, str]) -> CommandFeedResponse: - self.calls.append((path, dict(headers))) - response = self.responses.pop(0) - if isinstance(response, Exception): - raise response - return response - - -def _consumer( - tmp_path: Path, - transport: _Transport, - *, - kill_events: list | None = None, - mode_events: list | None = None, - failures: list | None = None, - state_journal: AppendOnlyOperationalJournal | None = None, - capital_adapter: CapitalEnvelopeAdapter | None = None, - now_fn=None, - request_nonces: list[str] | None = None, -) -> tuple[ - CoreCommandFeedConsumer, - AppendOnlyOperationalJournal, - CapitalEnvelopeAdapter, - list, - list, - list, -]: - clock = now_fn or (lambda: NOW) - nonce_values = iter( - request_nonces - or [REQUEST_NONCE_1, REQUEST_NONCE_2, REQUEST_NONCE_3] - ) - state = state_journal or AppendOnlyOperationalJournal( - tmp_path / "command-feed.jsonl", - now_fn=clock, - ) - adapter = capital_adapter or CapitalEnvelopeAdapter( - journal=AppendOnlyOperationalJournal( - tmp_path / "capital.jsonl", - now_fn=lambda: NOW, - ), - trusted_public_keys={CORE_SIGNER_KEY_ID: CORE_PUBLIC_KEY}, - expected_venue="dummy_kalshi", - expected_account_hash=ACCOUNT_HASH, - lineage_resolver=_UnusedLineageResolver(), - now_fn=clock, - ) - kills = [] if kill_events is None else kill_events - modes = [] if mode_events is None else mode_events - closed = [] if failures is None else failures - consumer = CoreCommandFeedConsumer( - transport=transport, - cell_token_provider=lambda: "dummy-cell-secret-token", - state_journal=state, - trusted_operator_public_keys={ - OPERATOR_SIGNER_KEY_ID: OPERATOR_PUBLIC_KEY - }, - trusted_checkpoint_public_keys={ - CORE_SIGNER_KEY_ID: CORE_PUBLIC_KEY - }, - capital_adapter=adapter, - kill_handler=kills.append, - mode_handler=modes.append, - fail_closed_handler=closed.append, - now_fn=clock, - request_nonce_fn=lambda: next(nonce_values), - ) - return consumer, state, adapter, kills, modes, closed - - -def test_signed_kill_is_delivered_and_restart_uses_durable_cursor(tmp_path): - kill = _command(_kill(sequence=1, active=True, generation=1), global_sequence=1) - first_transport = _Transport( - [ - CommandFeedResponse( - 200, - _page([kill], required_action="CANCEL_AND_RECONCILE"), - ) - ] - ) - consumer, state, adapter, kills, _, closed = _consumer( - tmp_path, - first_transport, - ) - - first = consumer.poll_once() - - assert first.page_accepted is True - assert first.cursor_sequence == 1 - assert first.submission_allowed is False - assert len(kills) == 1 - assert kills[0].body["active"] is True - assert closed - - next_transport = _Transport( - [ - CommandFeedResponse( - 200, - _page( - [], - after_sequence=1, - after_digest=kill["event_digest"], - required_action="CANCEL_AND_RECONCILE", - ), - ) - ] - ) - restarted, *_ = _consumer( - tmp_path, - next_transport, - state_journal=AppendOnlyOperationalJournal( - state.path, - now_fn=lambda: NOW, - ), - capital_adapter=adapter, - ) - second = restarted.poll_once() - - assert second.page_accepted is True - assert f"after=1&cursor={kill['event_digest']}" in next_transport.calls[0][0] - assert restarted.snapshot()["kill_envelope"]["body"]["active"] is True - - -def test_two_consumers_cannot_commit_from_the_same_cursor(tmp_path): - command = _command( - _kill(sequence=1, active=True, generation=1), - global_sequence=1, - ) - response = CommandFeedResponse( - 200, - _page([command], required_action="CANCEL_AND_RECONCILE"), - ) - state_path = tmp_path / "shared-command-feed.jsonl" - first, *_ = _consumer( - tmp_path, - _Transport([response]), - state_journal=AppendOnlyOperationalJournal( - state_path, - now_fn=lambda: NOW, - ), - ) - second, *_ = _consumer( - tmp_path, - _Transport([response]), - state_journal=AppendOnlyOperationalJournal( - state_path, - now_fn=lambda: NOW, - ), - ) - - with ThreadPoolExecutor(max_workers=2) as executor: - results = list( - executor.map(lambda consumer: consumer.poll_once(), [first, second]) - ) - - assert sorted(result.page_accepted for result in results) == [False, True] - restarted = AppendOnlyOperationalJournal( - state_path, - now_fn=lambda: NOW, - ) - states = restarted.events(kind="dumbmoney.command-feed.state") - assert restarted.healthy is True - assert len(states) == 2 - assert states[-1]["payload"]["cursor"]["sequence"] == 1 - assert states[-1]["payload"]["status"] == "FAIL_CLOSED" - - -def test_mode_and_capital_are_dispatched_without_positive_callbacks(tmp_path): - capital = _command(_capital(sequence=1), global_sequence=1) - mode = _command( - _mode(sequence=2, mode="PAUSED", revision=1), - global_sequence=2, - ) - inactive_kill = _command( - _kill(sequence=3, active=False, generation=1), - global_sequence=3, - ) - transport = _Transport( - [ - CommandFeedResponse( - 200, - _page( - [capital, mode, inactive_kill], - required_action="PAUSE_NEW_RISK", - ), - ) - ] - ) - consumer, _, adapter, kills, modes, _ = _consumer(tmp_path, transport) - - result = consumer.poll_once() - - assert result.page_accepted is True - assert result.commands_applied == 3 - assert result.submission_allowed is False - assert kills == [] - assert [item.body["mode"] for item in modes] == ["PAUSED"] - accepted = adapter.journal.events(kind="capital.envelope.accepted") - assert len(accepted) == 1 - assert accepted[0]["payload"]["wrapper"] == capital["envelope"] - - -def test_current_live_mode_kill_clear_and_capital_create_durable_readiness( - tmp_path, -): - commands = [ - _command(_capital(sequence=1), global_sequence=1), - _command( - _mode(sequence=2, mode="LIVE", revision=1), - global_sequence=2, - ), - _command( - _kill(sequence=3, active=False, generation=1), - global_sequence=3, - ), - ] - transport = _Transport( - [ - CommandFeedResponse( - 200, - _page(commands, required_action="APPLY_SIGNED_CONTROLS"), - ) - ] - ) - consumer, _, adapter, kills, modes, closed = _consumer( - tmp_path, - transport, - ) - - result = consumer.poll_once() - - assert result.page_accepted is True - assert result.commands_applied == 3 - assert result.submission_allowed is True - assert consumer.submission_allowed() is True - assert consumer.snapshot()["status"] == "READY" - assert len(adapter.journal.events(kind="capital.envelope.accepted")) == 1 - assert kills == [] - assert modes == [] - assert closed == [] - - -def test_expired_kill_clear_cannot_leave_submission_ready(tmp_path): - clock = [NOW] - commands = [ - _command( - _mode( - sequence=1, - mode="LIVE", - revision=1, - expires_at=NOW + timedelta(minutes=5), - ), - global_sequence=1, - ), - _command( - _kill( - sequence=2, - active=False, - generation=1, - expires_at=NOW + timedelta(seconds=5), - ), - global_sequence=2, - ), - ] - transport = _Transport( - [ - CommandFeedResponse( - 200, - _page(commands, required_action="APPLY_SIGNED_CONTROLS"), - ) - ] - ) - consumer, *_ = _consumer( - tmp_path, - transport, - now_fn=lambda: clock[0], - ) - - assert consumer.poll_once().submission_allowed is True - clock[0] = NOW + timedelta(seconds=6) - - assert consumer.submission_allowed() is False - - -def test_positive_controls_expiring_during_get_never_commit_ready(tmp_path): - clock = [NOW] - commands = [ - _command( - _mode( - sequence=1, - mode="LIVE", - revision=1, - expires_at=NOW + timedelta(seconds=1), - ), - global_sequence=1, - ), - _command( - _kill( - sequence=2, - active=False, - generation=1, - expires_at=NOW + timedelta(seconds=1), - ), - global_sequence=2, - ), - ] - response = CommandFeedResponse( - 200, - _page(commands, required_action="APPLY_SIGNED_CONTROLS"), - ) - - class SlowTransport: - def __call__(self, path, headers): - clock[0] = NOW + timedelta(seconds=2) - return response - - consumer, *_ = _consumer( - tmp_path, - SlowTransport(), - now_fn=lambda: clock[0], - ) - - result = consumer.poll_once() - - assert result.page_accepted is True - assert result.cursor_sequence == 2 - assert result.submission_allowed is False - assert consumer.snapshot()["status"] == "FAIL_CLOSED" - - -@pytest.mark.parametrize( - "tamper_kind", - ["unsigned_page_field", "signed_checkpoint", "command_projection"], -) -def test_checkpoint_tampering_never_advances_the_cursor( - tmp_path, - tamper_kind, -): - command = _command( - _kill(sequence=1, active=True, generation=1), - global_sequence=1, - ) - raw_page = _page( - [command], - required_action="CANCEL_AND_RECONCILE", - ) - page = json.loads(raw_page) - if tamper_kind == "unsigned_page_field": - page["required_action"] = "PAUSE_NEW_RISK" - elif tamper_kind == "signed_checkpoint": - page["checkpoint"]["required_action"] = "PAUSE_NEW_RISK" - else: - page["commands"][0]["authority_effect"] = "HISTORICAL_ONLY" - transport = _Transport( - [ - CommandFeedResponse( - 200, - canonical_json(page).encode("utf-8"), - ) - ] - ) - consumer, _, _, kills, _, closed = _consumer(tmp_path, transport) - - result = consumer.poll_once() - - assert result.page_accepted is False - assert result.cursor_sequence == 0 - assert kills == [] - assert len(closed) == 1 - - -def test_core_signed_malformed_ledger_proof_is_recomputed_and_rejected( - tmp_path, -): - command = _command( - _kill(sequence=1, active=True, generation=1), - global_sequence=1, - ) - page = json.loads( - _page([command], required_action="CANCEL_AND_RECONCILE") - ) - replacement = _hash("malformed-payload") - page["commands"][0]["ledger_proof"]["payload_digest"] = replacement - page["checkpoint"]["ordered_commands"][0]["ledger_proof"][ - "payload_digest" - ] = replacement - page["checkpoint_signature"] = _checkpoint_signature(page["checkpoint"]) - transport = _Transport( - [ - CommandFeedResponse( - 200, - canonical_json(page).encode("utf-8"), - ) - ] - ) - consumer, _, _, kills, _, closed = _consumer(tmp_path, transport) - - result = consumer.poll_once() - - assert result.page_accepted is False - assert result.cursor_sequence == 0 - assert kills == [] - assert len(closed) == 1 - - -def test_page_replayed_under_a_different_request_nonce_is_rejected(tmp_path): - command = _command( - _kill(sequence=1, active=True, generation=1), - global_sequence=1, - ) - captured_page = _page( - [command], - required_action="CANCEL_AND_RECONCILE", - request_nonce=REQUEST_NONCE_1, - ) - transport = _Transport([CommandFeedResponse(200, captured_page)]) - consumer, _, _, kills, _, closed = _consumer( - tmp_path, - transport, - request_nonces=[REQUEST_NONCE_2], - ) - - result = consumer.poll_once() - - assert result.page_accepted is False - assert result.cursor_sequence == 0 - assert kills == [] - assert f"request_nonce={REQUEST_NONCE_2}" in transport.calls[0][0] - assert len(closed) == 1 - - -@pytest.mark.parametrize("schema", ["kill", "capital"]) -def test_command_signer_roles_are_separate_and_fail_closed(tmp_path, schema): - if schema == "kill": - envelope = _kill( - sequence=1, - active=True, - generation=1, - signer_role="core", - ) - required_action = "CANCEL_AND_RECONCILE" - else: - envelope = _capital( - sequence=1, - signer_role="operator", - ) - required_action = "PAUSE_NEW_RISK" - command = _command(envelope, global_sequence=1) - transport = _Transport( - [ - CommandFeedResponse( - 200, - _page([command], required_action=required_action), - ) - ] - ) - consumer, _, adapter, kills, modes, closed = _consumer( - tmp_path, - transport, - ) - - result = consumer.poll_once() - - assert result.page_accepted is False - assert result.cursor_sequence == 0 - assert kills == [] - assert modes == [] - assert adapter.journal.events(kind="capital.envelope.accepted") == () - assert len(closed) == 1 - - -def test_backlog_and_irrelevant_ledger_gap_require_explicit_second_poll( - tmp_path, -): - mode = _command( - _mode(sequence=1, mode="LIVE", revision=1), - global_sequence=2, - ) - kill_clear = _command( - _kill(sequence=2, active=False, generation=1), - global_sequence=3, - ) - transport = _Transport( - [ - CommandFeedResponse( - 200, - _page( - [mode], - next_sequence=2, - ledger_head_sequence=3, - required_action="APPLY_SIGNED_CONTROLS", - ), - ), - CommandFeedResponse( - 200, - _page( - [kill_clear], - after_sequence=2, - after_digest=mode["event_digest"], - required_action="APPLY_SIGNED_CONTROLS", - request_nonce=REQUEST_NONCE_2, - ), - ), - ] - ) - consumer, *_ = _consumer(tmp_path, transport) - - catching_up = consumer.poll_once() - ready = consumer.poll_once() - - assert catching_up.page_accepted is True - assert catching_up.cursor_sequence == 2 - assert catching_up.submission_allowed is False - assert ready.page_accepted is True - assert ready.cursor_sequence == 3 - assert ready.submission_allowed is True - assert len(transport.calls) == 2 - - -@pytest.mark.parametrize( - "failure_kind", - ["tamper", "digest", "gap", "stale", "future", "unknown"], -) -def test_tamper_gap_and_stale_pages_retain_cursor_and_fail_closed( - tmp_path, - failure_kind, -): - envelope = _kill(sequence=1, active=True, generation=1) - command = _command(envelope, global_sequence=1) - if failure_kind == "tamper": - command["envelope"] = copy.deepcopy(envelope) - command["envelope"]["body"]["reason"] = "tampered" - body = _page([command], required_action="CANCEL_AND_RECONCILE") - elif failure_kind == "digest": - body = _page( - [command], - next_digest=_hash("wrong-ledger-digest"), - required_action="CANCEL_AND_RECONCILE", - ) - elif failure_kind == "gap": - body = _page( - [], - next_sequence=251, - next_digest=_hash("ledger-event:251"), - ledger_head_sequence=251, - required_action="PAUSE_NEW_RISK", - ) - elif failure_kind == "stale": - body = _page( - [], - required_action="PAUSE_NEW_RISK", - observed_at=NOW - timedelta(minutes=2), - ) - elif failure_kind == "future": - body = _page( - [], - required_action="PAUSE_NEW_RISK", - observed_at=NOW + timedelta(seconds=6), - ) - else: - command["body_schema"] = "dumbmoney.unknown-command.v1" - body = _page([command], required_action="CANCEL_AND_RECONCILE") - transport = _Transport([CommandFeedResponse(200, body)]) - consumer, _, _, kills, _, closed = _consumer(tmp_path, transport) - - result = consumer.poll_once() - - assert result.page_accepted is False - assert result.cursor_sequence == 0 - assert result.cursor_digest == ZERO_DIGEST - assert kills == [] - assert len(closed) == 1 - - -@pytest.mark.parametrize( - "response", - [ - CommandFeedResponse(401, b"not inspected"), - RuntimeError("loopback unavailable"), - ], -) -def test_auth_and_transport_failures_make_one_get_and_never_advance( - tmp_path, - response, -): - transport = _Transport([response]) - consumer, _, _, _, _, closed = _consumer(tmp_path, transport) - - result = consumer.poll_once() - - assert result.page_accepted is False - assert result.cursor_sequence == 0 - assert len(transport.calls) == 1 - assert transport.calls[0][1] == { - "Authorization": "Bearer dummy-cell-secret-token" - } - assert len(closed) == 1 - - -def test_expired_active_kill_advances_cursor_and_survives_restart_failure( - tmp_path, -): - expired = _kill( - sequence=1, - active=True, - generation=4, - not_before=NOW - timedelta(minutes=10), - expires_at=NOW - timedelta(minutes=5), - ) - command = _command(expired, global_sequence=1) - expired_clear = _command( - _kill( - sequence=2, - active=False, - generation=5, - not_before=NOW - timedelta(minutes=4), - expires_at=NOW - timedelta(minutes=3), - ), - global_sequence=2, - ) - transport = _Transport( - [ - CommandFeedResponse( - 200, - _page([command], required_action="CANCEL_AND_RECONCILE"), - ), - CommandFeedResponse( - 200, - _page( - [expired_clear], - after_sequence=1, - after_digest=command["event_digest"], - required_action="CANCEL_AND_RECONCILE", - request_nonce=REQUEST_NONCE_2, - ), - ), - ] - ) - consumer, state, adapter, kills, _, _ = _consumer(tmp_path, transport) - - result = consumer.poll_once() - - assert result.page_accepted is True - assert result.cursor_sequence == 1 - assert result.commands_applied == 1 - assert len(kills) == 1 - assert consumer.snapshot()["kill_generation_high_water"] == 4 - ignored_clear = consumer.poll_once() - assert ignored_clear.page_accepted is True - assert ignored_clear.cursor_sequence == 2 - assert ignored_clear.submission_allowed is False - assert consumer.snapshot()["kill_generation_high_water"] == 5 - assert consumer.snapshot()["kill_envelope"]["body"]["active"] is True - - failed_transport = _Transport([OSError("offline")]) - restarted, *_ = _consumer( - tmp_path, - failed_transport, - state_journal=AppendOnlyOperationalJournal( - state.path, - now_fn=lambda: NOW, - ), - capital_adapter=adapter, - ) - failed = restarted.poll_once() - - assert failed.page_accepted is False - assert failed.cursor_sequence == 2 - assert restarted.snapshot()["kill_envelope"]["body"]["active"] is True - assert restarted.submission_allowed() is False - - -def test_expired_pause_persists_while_live_and_future_capital_never_activate( - tmp_path, -): - expired_mode = _mode( - sequence=1, - mode="LIVE", - revision=7, - not_before=NOW - timedelta(minutes=10), - expires_at=NOW - timedelta(minutes=5), - ) - future_capital = _capital( - sequence=2, - fence=9, - not_before=NOW + timedelta(minutes=1), - expires_at=NOW + timedelta(minutes=2), - ) - expired_pause = _mode( - sequence=3, - mode="PAUSED", - revision=8, - not_before=NOW - timedelta(minutes=8), - expires_at=NOW - timedelta(minutes=4), - ) - commands = [ - _command(expired_mode, global_sequence=1), - _command(future_capital, global_sequence=2), - _command(expired_pause, global_sequence=3), - ] - transport = _Transport( - [ - CommandFeedResponse( - 200, - _page(commands, required_action="PAUSE_NEW_RISK"), - ) - ] - ) - consumer, _, adapter, _, modes, closed = _consumer(tmp_path, transport) - - result = consumer.poll_once() - snapshot = consumer.snapshot() - - assert result.page_accepted is True - assert result.cursor_sequence == 3 - assert result.commands_applied == 1 - assert result.submission_allowed is False - assert snapshot["desired_mode_envelope"]["body"]["mode"] == "PAUSED" - assert snapshot["mode_revision_high_water"] == 8 - assert snapshot["capital_fencing_high_water"] == 9 - assert adapter.journal.events(kind="capital.envelope.accepted") == () - assert [item.body["mode"] for item in modes] == ["PAUSED"] - assert closed diff --git a/tests/test_dumbmoney_execution_cycle.py b/tests/test_dumbmoney_execution_cycle.py deleted file mode 100644 index 48befdcd..00000000 --- a/tests/test_dumbmoney_execution_cycle.py +++ /dev/null @@ -1,68 +0,0 @@ -from __future__ import annotations - -import hashlib - -import pytest - -from live_firewall.dumbmoney_execution_cycle import ( - SealedDisabledExecutionCycle, -) - - -def _snapshot() -> dict: - return { - "schema": "dummy.kalshi-broker-truth.v1", - "venue": "dummy_kalshi", - "account_hash": hashlib.sha256(b"account").hexdigest(), - "subaccount_number": 0, - "observed_at": "2026-07-26T22:00:00Z", - "broker_snapshot_sha256": hashlib.sha256(b"snapshot").hexdigest(), - "flat_book_observed": True, - "total_exposure_cents": 0, - "open_order_count": 0, - "market_exposure_cents": {}, - "correlated_exposure_cents": {}, - "unresolved_open_orders": 0, - "unresolved_positions": 0, - } - - -def test_sealed_cycle_is_snapshot_bound_and_has_no_submission_surface() -> None: - cycle = SealedDisabledExecutionCycle() - snapshot = _snapshot() - - result = cycle( - capital_adapter=object(), # type: ignore[arg-type] - command_feed=object(), # type: ignore[arg-type] - broker_snapshot=snapshot, - ) - - assert result == { - "schema": "dummy.dumbmoney-execution-cycle.v1", - "status": "BLOCKED", - "broker_contacted": False, - "orders_submitted": 0, - "broker_snapshot_sha256": snapshot["broker_snapshot_sha256"], - } - assert cycle.submission_capable is False - assert not hasattr(cycle, "broker") - assert not hasattr(cycle, "submit") - - -def test_sealed_cycle_rejects_non_exact_or_unbound_snapshot() -> None: - cycle = SealedDisabledExecutionCycle() - extra = {**_snapshot(), "unexpected": True} - with pytest.raises(ValueError, match="fields mismatch"): - cycle( - capital_adapter=object(), # type: ignore[arg-type] - command_feed=object(), # type: ignore[arg-type] - broker_snapshot=extra, - ) - - malformed = {**_snapshot(), "broker_snapshot_sha256": "not-a-digest"} - with pytest.raises(ValueError, match="digest is invalid"): - cycle( - capital_adapter=object(), # type: ignore[arg-type] - command_feed=object(), # type: ignore[arg-type] - broker_snapshot=malformed, - ) diff --git a/tests/test_dumbmoney_journal_anchor.py b/tests/test_dumbmoney_journal_anchor.py deleted file mode 100644 index 30be2d17..00000000 --- a/tests/test_dumbmoney_journal_anchor.py +++ /dev/null @@ -1,302 +0,0 @@ -from __future__ import annotations - -import base64 -import hashlib -import json -from datetime import datetime, timedelta, timezone -from typing import Any - -import pytest -from cryptography.hazmat.primitives.asymmetric.ed25519 import ( - Ed25519PrivateKey, -) - -from live_firewall.dumbmoney_journal_anchor import ( - ANCHOR_BODY_SCHEMA, - ANCHOR_CHECKPOINT_SCHEMA, - ANCHOR_REQUEST_SCHEMA, - ANCHOR_RESPONSE_SCHEMA, - CoreJournalAnchorClient, - JournalAnchorError, - JournalAnchorResponse, -) -from live_firewall.operational_journal import canonical_json, sha256_json - - -NOW = datetime(2026, 7, 26, 22, 0, 0, tzinfo=timezone.utc) -ACCOUNT_HASH = hashlib.sha256(b"dummy-account").hexdigest() -PRIVATE_KEY = Ed25519PrivateKey.from_private_bytes(bytes(range(32))) -PUBLIC_KEY = PRIVATE_KEY.public_key().public_bytes_raw() -SIGNER_KEY_ID = hashlib.sha256(PUBLIC_KEY).hexdigest() -ZERO_DIGEST = "0" * 64 - - -def _z(value: datetime) -> str: - return value.astimezone(timezone.utc).isoformat().replace("+00:00", "Z") - - -def _hash(label: str) -> str: - return hashlib.sha256(label.encode("utf-8")).hexdigest() - - -def _signature(value: dict[str, Any]) -> str: - return ( - base64.urlsafe_b64encode( - PRIVATE_KEY.sign(canonical_json(value).encode("utf-8")) - ) - .decode("ascii") - .rstrip("=") - ) - - -def _signed_anchor( - body: dict[str, Any], - *, - observed_at: datetime, -) -> dict[str, Any]: - identity = { - "schema": "dumbmoney.signed-envelope.v1", - "source_id": "dumbmoney-core", - "source_sequence": 1, - "correlation_id": "journal-anchor:dummy_kalshi:test-journal", - "causation_id": None, - "nonce": _hash("anchor-event-nonce"), - "not_before": _z(observed_at), - "expires_at": _z(observed_at + timedelta(seconds=120)), - "body_schema": ANCHOR_BODY_SCHEMA, - "body_digest": sha256_json(body), - "body": body, - "signature_algorithm": "Ed25519", - "signer_key_id": SIGNER_KEY_ID, - } - envelope = {**identity, "event_id": sha256_json(identity)} - envelope["signature"] = _signature(envelope) - return envelope - - -def _response( - request: dict[str, Any], - *, - observed_at: datetime = NOW, - reused: bool = False, -) -> dict[str, Any]: - previous = ZERO_DIGEST - anchor_identity = { - "schema": ANCHOR_BODY_SCHEMA, - "venue": "dummy_kalshi", - "account_hash": request["account_hash"], - "journal_name": request["journal_name"], - "journal_schema": request["journal_schema"], - "journal_stream_id": request["journal_stream_id"], - "journal_sequence": request["journal_sequence"], - "journal_head_sha256": request["journal_head_sha256"], - "previous_anchor_body_digest": previous, - } - body = { - **anchor_identity, - "anchor_id": sha256_json(anchor_identity), - "anchored_at": _z(observed_at), - } - envelope = _signed_anchor(body, observed_at=observed_at) - event_material = { - "global_sequence": 1, - "event_id": envelope["event_id"], - "source_id": envelope["source_id"], - "source_sequence": envelope["source_sequence"], - "signer_key_id": envelope["signer_key_id"], - "nonce": envelope["nonce"], - "event_schema": envelope["body_schema"], - "observed_at": _z(observed_at), - "received_at": _z(observed_at), - "correlation_id": envelope["correlation_id"], - "causation_id": envelope["causation_id"], - "payload_digest": envelope["body_digest"], - "previous_source_digest": ZERO_DIGEST, - "previous_global_digest": ZERO_DIGEST, - } - event_digest = sha256_json(event_material) - proof = { - "schema": "dumbmoney.ledger-event-proof.v1", - **event_material, - "event_digest": event_digest, - } - checkpoint = { - "schema": ANCHOR_CHECKPOINT_SCHEMA, - "cell_id": "dummy_kalshi", - "request_nonce": request["request_nonce"], - "account_hash": request["account_hash"], - "journal_name": request["journal_name"], - "journal_schema": request["journal_schema"], - "journal_stream_id": request["journal_stream_id"], - "journal_sequence": request["journal_sequence"], - "journal_head_sha256": request["journal_head_sha256"], - "anchor_body_digest": envelope["body_digest"], - "anchor_event_digest": event_digest, - "reused": reused, - "observed_at": _z(observed_at), - } - return { - "schema": ANCHOR_RESPONSE_SCHEMA, - "cell_id": "dummy_kalshi", - "request_nonce": request["request_nonce"], - "observed_at": _z(observed_at), - "reused": reused, - "anchor_envelope": envelope, - "ledger_proof": proof, - "checkpoint": checkpoint, - "checkpoint_signature": { - "algorithm": "Ed25519", - "signer_key_id": SIGNER_KEY_ID, - "signature": _signature(checkpoint), - }, - } - - -class _Transport: - def __init__( - self, - mutate: Any = None, - *, - status_code: int = 200, - ) -> None: - self.mutate = mutate - self.status_code = status_code - self.calls: list[tuple[str, dict[str, str], dict[str, Any]]] = [] - - def __call__( - self, - path: str, - headers: dict[str, str], - body: bytes, - ) -> JournalAnchorResponse: - request = json.loads(body) - self.calls.append((path, dict(headers), request)) - payload = _response(request) - if self.mutate is not None: - self.mutate(payload) - return JournalAnchorResponse( - status_code=self.status_code, - body=canonical_json(payload).encode("utf-8"), - ) - - -def _client(transport: Any, *, now: datetime = NOW) -> CoreJournalAnchorClient: - return CoreJournalAnchorClient( - transport=transport, - cell_token_provider=lambda: "t" * 64, - trusted_core_public_keys={SIGNER_KEY_ID: PUBLIC_KEY}, - expected_account_hash=ACCOUNT_HASH, - request_nonce_fn=lambda: _hash("request-nonce"), - now_fn=lambda: now, - ) - - -def test_exact_core_anchor_checkpoint_and_ledger_proof_are_accepted() -> None: - transport = _Transport() - client = _client(transport) - head = _hash("journal-head") - - result = client.anchor( - journal_name="capital-operational", - journal_schema="dummy.sqlite-operational-journal.v1", - journal_sequence=7, - journal_head_sha256=head, - ) - - assert result.journal_sequence == 7 - assert result.journal_head_sha256 == head - assert result.reused is False - path, headers, request = transport.calls[0] - assert path == "/v1/cells/dummy_kalshi/journal-heads:anchor" - assert headers == { - "Authorization": f"Bearer {'t' * 64}", - "Content-Type": "application/json", - } - assert request["schema"] == ANCHOR_REQUEST_SCHEMA - assert request["journal_stream_id"] == client.stream_id( - "capital-operational" - ) - - -def test_checkpoint_tamper_fails_closed() -> None: - def mutate(payload: dict[str, Any]) -> None: - payload["checkpoint"]["journal_sequence"] = 6 - - with pytest.raises( - JournalAnchorError, - match="signature is invalid", - ): - _client(_Transport(mutate)).anchor( - journal_name="capital-operational", - journal_schema="dummy.sqlite-operational-journal.v1", - journal_sequence=7, - journal_head_sha256=_hash("journal-head"), - ) - - -def test_envelope_tamper_is_normalized_to_anchor_error() -> None: - def mutate(payload: dict[str, Any]) -> None: - payload["anchor_envelope"]["body"]["journal_sequence"] = 6 - - with pytest.raises( - JournalAnchorError, - match="anchor envelope is invalid", - ): - _client(_Transport(mutate)).anchor( - journal_name="capital-operational", - journal_schema="dummy.sqlite-operational-journal.v1", - journal_sequence=7, - journal_head_sha256=_hash("journal-head"), - ) - - -def test_stale_checkpoint_and_core_rejection_fail_closed() -> None: - def stale( - path: str, - headers: dict[str, str], - body: bytes, - ) -> JournalAnchorResponse: - del path, headers - request = json.loads(body) - payload = _response( - request, - observed_at=NOW - timedelta(seconds=31), - ) - return JournalAnchorResponse( - 200, - canonical_json(payload).encode("utf-8"), - ) - - with pytest.raises(JournalAnchorError, match="is not current"): - _client(stale).anchor( - journal_name="command-feed", - journal_schema="dummy.sqlite-operational-journal.v1", - journal_sequence=0, - journal_head_sha256=ZERO_DIGEST, - ) - - with pytest.raises(JournalAnchorError, match="rejected"): - _client(_Transport(status_code=409)).anchor( - journal_name="command-feed", - journal_schema="dummy.sqlite-operational-journal.v1", - journal_sequence=0, - journal_head_sha256=ZERO_DIGEST, - ) - - -def test_sequence_zero_and_zero_head_must_match() -> None: - client = _client(_Transport()) - with pytest.raises(JournalAnchorError, match="zero head"): - client.anchor( - journal_name="command-feed", - journal_schema="dummy.sqlite-operational-journal.v1", - journal_sequence=0, - journal_head_sha256=_hash("not-empty"), - ) - with pytest.raises(JournalAnchorError, match="zero head"): - client.anchor( - journal_name="command-feed", - journal_schema="dummy.sqlite-operational-journal.v1", - journal_sequence=1, - journal_head_sha256=ZERO_DIGEST, - ) diff --git a/tests/test_dumbmoney_kalshi_broker_truth.py b/tests/test_dumbmoney_kalshi_broker_truth.py deleted file mode 100644 index 7abc31b1..00000000 --- a/tests/test_dumbmoney_kalshi_broker_truth.py +++ /dev/null @@ -1,831 +0,0 @@ -from __future__ import annotations - -import base64 -import hashlib -from collections import Counter -from datetime import datetime, timezone -from pathlib import Path -from types import SimpleNamespace -from typing import Any -from unittest.mock import Mock - -import httpx -import pytest -from cryptography.hazmat.primitives import hashes, serialization -from cryptography.hazmat.primitives.asymmetric import padding, rsa -from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey - -from live_firewall import dumbmoney_windows_service as windows_service -from live_firewall.dumbmoney_capital import verify_signed_envelope -from live_firewall.kalshi_broker_truth import ( - KALSHI_API_PREFIX, - KALSHI_PRODUCTION_ORIGIN, - KalshiBrokerTruthError, - KalshiBrokerTruthProvider, -) -from live_firewall.kalshi_reconciliation import ( - KalshiReconciliationReader, -) - - -NOW = datetime(2026, 7, 26, 22, 0, tzinfo=timezone.utc) -KEY_ID = "test-key-id" -ACCOUNT_HASH = windows_service.kalshi_account_hash(KEY_ID, 0) - - -@pytest.fixture(scope="module") -def private_key() -> rsa.RSAPrivateKey: - return rsa.generate_private_key(public_exponent=65_537, key_size=2_048) - - -@pytest.fixture(scope="module") -def private_key_pem(private_key: rsa.RSAPrivateKey) -> bytes: - return private_key.private_bytes( - serialization.Encoding.PEM, - serialization.PrivateFormat.PKCS8, - serialization.NoEncryption(), - ) - - -def _client( - handler: Any, -) -> httpx.Client: - return httpx.Client( - base_url=f"{KALSHI_PRODUCTION_ORIGIN}{KALSHI_API_PREFIX}/", - transport=httpx.MockTransport(handler), - trust_env=False, - follow_redirects=False, - ) - - -def _provider( - private_key_pem: bytes, - handler: Any, - **kwargs: Any, -) -> KalshiBrokerTruthProvider: - return KalshiBrokerTruthProvider( - api_key_id=KEY_ID, - private_key_pem=private_key_pem, - expected_account_hash=ACCOUNT_HASH, - subaccount_number=0, - client=_client(handler), - clock=lambda: NOW, - **kwargs, - ) - - -def _flat_handler(requests: list[httpx.Request]) -> Any: - def handler(request: httpx.Request) -> httpx.Response: - requests.append(request) - if request.url.path.endswith("/portfolio/balance"): - payload = { - "balance": 123, - "balance_dollars": "1.2300", - "portfolio_value": 0, - "updated_ts": 1_721_000_000, - "balance_breakdown": [], - } - elif request.url.path.endswith("/portfolio/positions"): - payload = { - "market_positions": [], - "event_positions": [], - "cursor": "", - } - elif request.url.path.endswith("/portfolio/orders"): - payload = {"orders": [], "cursor": ""} - else: - raise AssertionError(f"unexpected path: {request.url.path}") - return httpx.Response(200, json=payload, request=request) - - return handler - - -def test_flat_snapshot_is_signed_scoped_stable_and_network_read_only( - private_key: rsa.RSAPrivateKey, - private_key_pem: bytes, -) -> None: - requests: list[httpx.Request] = [] - provider = _provider(private_key_pem, _flat_handler(requests)) - try: - snapshot = provider.snapshot() - finally: - provider.close() - - assert snapshot == { - "schema": "dummy.kalshi-broker-truth.v1", - "venue": "dummy_kalshi", - "account_hash": ACCOUNT_HASH, - "subaccount_number": 0, - "observed_at": "2026-07-26T22:00:00Z", - "broker_snapshot_sha256": snapshot["broker_snapshot_sha256"], - "flat_book_observed": True, - "total_exposure_cents": 0, - "open_order_count": 0, - "market_exposure_cents": {}, - "correlated_exposure_cents": {}, - "unresolved_open_orders": 0, - "unresolved_positions": 0, - } - assert len(snapshot["broker_snapshot_sha256"]) == 64 - assert [request.method for request in requests] == ["GET"] * 5 - assert Counter(request.url.path for request in requests) == { - f"{KALSHI_API_PREFIX}/portfolio/balance": 1, - f"{KALSHI_API_PREFIX}/portfolio/positions": 2, - f"{KALSHI_API_PREFIX}/portfolio/orders": 2, - } - for request in requests: - assert request.url.host == "external-api.kalshi.com" - assert request.url.scheme == "https" - assert request.url.params["subaccount"] == "0" - assert request.headers["KALSHI-ACCESS-KEY"] == KEY_ID - timestamp = request.headers["KALSHI-ACCESS-TIMESTAMP"] - signature = request.headers["KALSHI-ACCESS-SIGNATURE"] - private_key.public_key().verify( - base64.b64decode(signature), - f"{timestamp}GET{request.url.path}".encode(), - padding.PSS( - mgf=padding.MGF1(hashes.SHA256()), - salt_length=padding.PSS.DIGEST_LENGTH, - ), - hashes.SHA256(), - ) - positions = [ - request - for request in requests - if request.url.path.endswith("/portfolio/positions") - ] - orders = [ - request - for request in requests - if request.url.path.endswith("/portfolio/orders") - ] - assert all(request.url.params["limit"] == "1000" for request in positions) - assert all( - request.url.params["count_filter"] == "position" - for request in positions - ) - assert all(request.url.params["status"] == "resting" for request in orders) - - -def test_paginated_exposure_is_complete_and_conservative( - private_key_pem: bytes, -) -> None: - calls: Counter[tuple[str, str]] = Counter() - - def handler(request: httpx.Request) -> httpx.Response: - path = request.url.path - cursor = request.url.params.get("cursor", "") - calls[(path, cursor)] += 1 - if path.endswith("/portfolio/balance"): - payload = { - "balance": 500, - "balance_dollars": "5.0000", - "portfolio_value": 25, - "updated_ts": 1_721_000_001, - } - elif path.endswith("/portfolio/positions") and not cursor: - payload = { - "market_positions": [ - { - "ticker": "KXTEST-A", - "position_fp": "1.00", - "market_exposure_dollars": "0.1234", - "last_updated_ts": "2026-07-26T21:59:00Z", - } - ], - "event_positions": [ - { - "event_ticker": "KXTEST", - "event_exposure_dollars": "0.2000", - } - ], - "cursor": "positions-next", - } - elif path.endswith("/portfolio/positions"): - assert cursor == "positions-next" - payload = { - "market_positions": [ - { - "ticker": "KXOTHER-B", - "position_fp": "-2.00", - "market_exposure_dollars": "-0.0001", - "last_updated_ts": "2026-07-26T21:59:30Z", - } - ], - "event_positions": [ - { - "event_ticker": "KXOTHER", - "event_exposure_dollars": "0.0500", - } - ], - "cursor": "", - } - elif path.endswith("/portfolio/orders") and not cursor: - payload = { - "orders": [ - { - "order_id": "order-a", - "ticker": "KXTEST-A", - "remaining_count_fp": "1.00", - "yes_price_dollars": "0.4000", - "no_price_dollars": "0.6000", - "subaccount_number": 0, - } - ], - "cursor": "orders-next", - } - elif path.endswith("/portfolio/orders"): - assert cursor == "orders-next" - payload = { - "orders": [ - { - "order_id": "order-b", - "ticker": "KXOTHER-B", - "remaining_count_fp": "2.00", - "yes_price_dollars": "0.7500", - "no_price_dollars": "0.2500", - "subaccount_number": 0, - } - ], - "cursor": "", - } - else: - raise AssertionError(path) - return httpx.Response(200, json=payload, request=request) - - provider = _provider(private_key_pem, handler) - try: - snapshot = provider.snapshot() - finally: - provider.close() - - assert snapshot["flat_book_observed"] is False - assert snapshot["total_exposure_cents"] == 25 - assert snapshot["market_exposure_cents"] == { - "KXOTHER-B": 1, - "KXTEST-A": 13, - } - assert snapshot["correlated_exposure_cents"] == { - "KXOTHER": 5, - "KXTEST": 20, - } - assert snapshot["open_order_count"] == 2 - assert snapshot["unresolved_open_orders"] == 2 - assert snapshot["unresolved_positions"] == 2 - assert calls[ - (f"{KALSHI_API_PREFIX}/portfolio/positions", "") - ] == 2 - assert calls[ - (f"{KALSHI_API_PREFIX}/portfolio/positions", "positions-next") - ] == 2 - assert calls[ - (f"{KALSHI_API_PREFIX}/portfolio/orders", "") - ] == 2 - assert calls[ - (f"{KALSHI_API_PREFIX}/portfolio/orders", "orders-next") - ] == 2 - - -def test_snapshot_rejects_state_that_changes_between_double_reads( - private_key_pem: bytes, -) -> None: - position_reads = 0 - - def handler(request: httpx.Request) -> httpx.Response: - nonlocal position_reads - if request.url.path.endswith("/portfolio/balance"): - payload = { - "balance": 100, - "balance_dollars": "1.0000", - "portfolio_value": 0, - "updated_ts": 1, - } - elif request.url.path.endswith("/portfolio/orders"): - payload = {"orders": [], "cursor": ""} - else: - position_reads += 1 - markets = ( - [] - if position_reads == 1 - else [ - { - "ticker": "KXCHANGED", - "position_fp": "1.00", - "market_exposure_dollars": "0.1000", - "last_updated_ts": "2026-07-26T21:59:00Z", - } - ] - ) - payload = { - "market_positions": markets, - "event_positions": [], - "cursor": "", - } - return httpx.Response(200, json=payload, request=request) - - provider = _provider(private_key_pem, handler) - try: - with pytest.raises( - KalshiBrokerTruthError, - match="changed during reconciliation", - ): - provider.snapshot() - finally: - provider.close() - - -@pytest.mark.parametrize( - ("market_positions", "event_positions", "message"), - [ - ( - [ - { - "ticker": "KXFUTURE", - "position_fp": "1.00", - "market_exposure_dollars": "0.1000", - "last_updated_ts": "2026-07-26T22:00:06Z", - } - ], - [], - "timestamp is in the future", - ), - ( - [], - [ - { - "event_ticker": "KXORPHAN", - "event_exposure_dollars": "0.1000", - } - ], - "event exposure exists without a market position", - ), - ], -) -def test_snapshot_rejects_internally_inconsistent_position_evidence( - private_key_pem: bytes, - market_positions: list[dict[str, Any]], - event_positions: list[dict[str, Any]], - message: str, -) -> None: - def handler(request: httpx.Request) -> httpx.Response: - if request.url.path.endswith("/portfolio/balance"): - payload = { - "balance": 100, - "balance_dollars": "1.0000", - "portfolio_value": 0, - "updated_ts": 1, - } - elif request.url.path.endswith("/portfolio/positions"): - payload = { - "market_positions": market_positions, - "event_positions": event_positions, - "cursor": "", - } - else: - payload = {"orders": [], "cursor": ""} - return httpx.Response(200, json=payload, request=request) - - provider = _provider(private_key_pem, handler) - try: - with pytest.raises(KalshiBrokerTruthError, match=message): - provider.snapshot() - finally: - provider.close() - - -def test_snapshot_rejects_incomplete_pagination( - private_key_pem: bytes, -) -> None: - def handler(request: httpx.Request) -> httpx.Response: - if request.url.path.endswith("/portfolio/balance"): - payload = { - "balance": 100, - "balance_dollars": "1.0000", - "portfolio_value": 0, - "updated_ts": 1, - } - else: - payload = { - "market_positions": [], - "event_positions": [], - "cursor": "still-more", - } - return httpx.Response(200, json=payload, request=request) - - provider = _provider( - private_key_pem, - handler, - maximum_pages=1, - ) - try: - with pytest.raises( - KalshiBrokerTruthError, - match="positions pagination is incomplete", - ): - provider.snapshot() - finally: - provider.close() - - -@pytest.mark.parametrize( - "body", - [ - b'{"balance":100,"balance":200,"balance_dollars":"1.0000",' - b'"portfolio_value":0,"updated_ts":1}', - b'{"balance":NaN,"balance_dollars":"1.0000",' - b'"portfolio_value":0,"updated_ts":1}', - ], -) -def test_snapshot_rejects_non_strict_broker_json( - private_key_pem: bytes, - body: bytes, -) -> None: - def handler(request: httpx.Request) -> httpx.Response: - return httpx.Response( - 200, - content=body, - headers={"Content-Type": "application/json"}, - request=request, - ) - - provider = _provider(private_key_pem, handler) - try: - with pytest.raises( - KalshiBrokerTruthError, - match="strict bounded JSON", - ): - provider.snapshot() - finally: - provider.close() - - -def test_snapshot_rejects_order_from_another_subaccount( - private_key_pem: bytes, -) -> None: - def handler(request: httpx.Request) -> httpx.Response: - if request.url.path.endswith("/portfolio/balance"): - payload = { - "balance": 100, - "balance_dollars": "1.0000", - "portfolio_value": 0, - "updated_ts": 1, - } - elif request.url.path.endswith("/portfolio/positions"): - payload = { - "market_positions": [], - "event_positions": [], - "cursor": "", - } - else: - payload = { - "orders": [ - { - "order_id": "wrong-account", - "ticker": "KXTEST", - "remaining_count_fp": "1.00", - "yes_price_dollars": "0.5000", - "no_price_dollars": "0.5000", - "subaccount_number": 1, - } - ], - "cursor": "", - } - return httpx.Response(200, json=payload, request=request) - - provider = _provider(private_key_pem, handler) - try: - with pytest.raises( - KalshiBrokerTruthError, - match="different subaccount", - ): - provider.snapshot() - finally: - provider.close() - - -def test_production_constructor_is_proxy_isolated_and_origin_pinned( - monkeypatch: pytest.MonkeyPatch, - private_key_pem: bytes, -) -> None: - constructed = Mock() - monkeypatch.setattr( - "live_firewall.kalshi_broker_truth.httpx.Client", - constructed, - ) - KalshiBrokerTruthProvider( - api_key_id=KEY_ID, - private_key_pem=private_key_pem, - expected_account_hash=ACCOUNT_HASH, - subaccount_number=0, - clock=lambda: NOW, - ) - - assert constructed.call_count == 1 - kwargs = constructed.call_args.kwargs - assert kwargs["base_url"] == ( - "https://external-api.kalshi.com/trade-api/v2/" - ) - assert kwargs["trust_env"] is False - assert kwargs["follow_redirects"] is False - assert kwargs["limits"].max_connections == 1 - - -def test_service_main_wires_credential_owned_truth_without_contacting_broker( - monkeypatch: pytest.MonkeyPatch, - tmp_path: Path, - private_key_pem: bytes, -) -> None: - config = SimpleNamespace( - data_root=tmp_path / "data", - expected_account_hash=ACCOUNT_HASH, - kalshi_subaccount_number=0, - ) - secrets = SimpleNamespace( - kalshi_key_id=KEY_ID, - kalshi_private_key_pem=private_key_pem, - ) - provider = object() - captured: dict[str, Any] = {} - - monkeypatch.setenv("PROGRAMDATA", str(tmp_path)) - monkeypatch.setattr( - windows_service, - "load_runner_config", - lambda *_args: config, - ) - monkeypatch.setattr( - windows_service, - "load_secrets", - lambda *_args: secrets, - ) - monkeypatch.setattr( - windows_service, - "WindowsCredentialManager", - lambda: object(), - ) - monkeypatch.setattr( - windows_service, - "LoopbackCoreTransport", - lambda: object(), - ) - - def truth_factory(**kwargs: Any) -> object: - captured["truth_kwargs"] = kwargs - return provider - - class Service: - def __init__( - self, - _config: Any, - _secrets: Any, - **kwargs: Any, - ) -> None: - captured["service_kwargs"] = kwargs - - def run_forever(self, _stop_event: Any) -> None: - return - - monkeypatch.setattr( - windows_service, - "KalshiBrokerTruthProvider", - truth_factory, - ) - monkeypatch.setattr( - windows_service, - "DumbMoneyDummyKalshiService", - Service, - ) - monkeypatch.setattr(windows_service.signal, "signal", lambda *_args: None) - - result = windows_service.main( - [ - "--core-endpoint-ref", - windows_service.CORE_ENDPOINT_REF, - "--core-cell-token-target", - windows_service.CELL_TOKEN_TARGET_REF, - "--kalshi-key-id-target", - windows_service.KALSHI_KEY_ID_TARGET_REF, - "--kalshi-private-key-target", - windows_service.KALSHI_PRIVATE_KEY_TARGET_REF, - "--readiness-signing-key-target", - windows_service.READINESS_KEY_TARGET_REF, - "--start-mode", - windows_service.START_MODE, - "--readiness-ref", - windows_service.READINESS_REF, - "--config-sha256", - "b" * 64, - ] - ) - - assert result == 0 - assert captured["truth_kwargs"] == { - "api_key_id": KEY_ID, - "private_key_pem": private_key_pem, - "expected_account_hash": ACCOUNT_HASH, - "subaccount_number": 0, - } - assert captured["service_kwargs"]["broker_truth"] is provider - cycle = captured["service_kwargs"]["execution_cycle"] - assert isinstance(cycle, windows_service.SealedDisabledExecutionCycle) - assert cycle.submission_capable is False - - -def test_service_close_closes_broker_truth( - monkeypatch: pytest.MonkeyPatch, -) -> None: - source = ( - Path(windows_service.__file__) - .read_text(encoding="utf-8") - .replace("\r\n", "\n") - ) - assert 'getattr(self.broker_truth, "close", None)' in source - assert "broker_close()" in source - - -def test_terminal_reader_combines_live_and_historical_fills_and_signs( - private_key_pem: bytes, -) -> None: - signing_key = Ed25519PrivateKey.from_private_bytes(bytes([6]) * 32) - public_key = signing_key.public_key().public_bytes_raw() - signer_id = hashlib.sha256(public_key).hexdigest() - requests: list[httpx.Request] = [] - - order = { - "order_id": "broker-order-1", - "user_id": "fixture-user", - "client_order_id": "proposal-1", - "ticker": "KXTEST-26JUL", - "side": "yes", - "action": "buy", - "outcome_side": "yes", - "book_side": "bid", - "type": "limit", - "status": "executed", - "yes_price_dollars": "0.500000", - "no_price_dollars": "0.500000", - "fill_count_fp": "1.00", - "remaining_count_fp": "0.00", - "initial_count_fp": "1.00", - "taker_fill_cost_dollars": "0.500000", - "maker_fill_cost_dollars": "0.000000", - "taker_fees_dollars": "0.020000", - "maker_fees_dollars": "0.000000", - "expiration_time": "2026-07-26T22:30:00Z", - "created_time": "2026-07-26T21:59:00Z", - "last_update_time": "2026-07-26T21:59:30Z", - "self_trade_prevention_type": "taker_at_cross", - "order_group_id": "", - "cancel_order_on_pause": True, - "subaccount_number": 0, - } - fill = { - "fill_id": "fill-1", - "trade_id": "trade-1", - "order_id": "broker-order-1", - "ticker": "KXTEST-26JUL", - "market_ticker": "KXTEST-26JUL", - "side": "yes", - "action": "buy", - "outcome_side": "yes", - "book_side": "bid", - "count_fp": "1.00", - "yes_price_dollars": "0.500000", - "no_price_dollars": "0.500000", - "is_taker": True, - "fee_cost": "0.020000", - "created_time": "2026-07-26T21:59:30Z", - "subaccount_number": 0, - "ts": 1_721_000_000, - } - - def handler(request: httpx.Request) -> httpx.Response: - requests.append(request) - if request.url.path.endswith("/orders"): - payload = {"orders": [order], "cursor": ""} - elif request.url.path.endswith("/fills"): - payload = {"fills": [fill], "cursor": ""} - else: - raise AssertionError(request.url.path) - return httpx.Response(200, json=payload, request=request) - - provider = _provider(private_key_pem, handler) - reader = KalshiReconciliationReader( - broker_truth=provider, - witness_signing_private_key=signing_key, - ) - reservation = { - "reservation_id": hashlib.sha256(b"reservation").hexdigest(), - "proposal_id": "proposal-1", - "market_ticker": "KXTEST-26JUL", - "contract_ticker": "KXTEST-26JUL", - "side": "yes", - "size": 1, - "price_cents": 50, - } - try: - with pytest.raises( - KalshiBrokerTruthError, - match="differs from the capital reservation", - ): - reader.terminal_reconciliation_witness( - {**reservation, "price_cents": 49} - ) - requests.clear() - wrapper = reader.terminal_reconciliation_witness(reservation) - finally: - provider.close() - - assert wrapper is not None - signed = verify_signed_envelope( - wrapper, - trusted_public_keys={signer_id: public_key}, - expected_body_schema=( - "dummy.kalshi-order-terminal-witness.v1" - ), - require_active=False, - ) - assert signed.body["terminal_status"] == "executed" - assert signed.body["fill_count"] == 1 - assert signed.body["fill_cost_cents"] == 50 - assert signed.body["fee_cents"] == 2 - assert signed.body["average_fill_price_cents"] == 50 - assert signed.body["fill_ids"] == ["fill-1"] - assert Counter(request.url.path for request in requests) == { - f"{KALSHI_API_PREFIX}/portfolio/orders": 2, - f"{KALSHI_API_PREFIX}/historical/orders": 2, - f"{KALSHI_API_PREFIX}/portfolio/fills": 2, - f"{KALSHI_API_PREFIX}/historical/fills": 2, - } - live_requests = [ - request for request in requests - if "/portfolio/" in request.url.path - ] - assert all( - request.url.params["subaccount"] == "0" - for request in live_requests - ) - - -def test_settlement_reader_requires_stable_position_absence( - private_key_pem: bytes, -) -> None: - signing_key = Ed25519PrivateKey.from_private_bytes(bytes([5]) * 32) - position_reads = 0 - - def handler(request: httpx.Request) -> httpx.Response: - nonlocal position_reads - if request.url.path.endswith("/positions"): - position_reads += 1 - payload = { - "market_positions": [], - "event_positions": [], - "cursor": "", - } - elif request.url.path.endswith("/settlements"): - payload = { - "settlements": [ - { - "ticker": "KXTEST-26JUL", - "event_ticker": "KXTEST", - "market_result": "yes", - "yes_count_fp": "1.00", - "yes_total_cost_dollars": "0.500000", - "no_count_fp": "0.00", - "no_total_cost_dollars": "0.000000", - "revenue": 100, - "settled_time": "2026-07-26T21:59:59Z", - "fee_cost": "0.020000", - "value": 100, - } - ], - "cursor": "", - } - else: - raise AssertionError(request.url.path) - return httpx.Response(200, json=payload, request=request) - - provider = _provider(private_key_pem, handler) - reader = KalshiReconciliationReader( - broker_truth=provider, - witness_signing_private_key=signing_key, - ) - position = { - "position_exposure_id": hashlib.sha256(b"position").hexdigest(), - "reservation_id": hashlib.sha256(b"reservation").hexdigest(), - "proposal_id": "proposal-1", - "contract_ticker": "KXTEST-26JUL", - "side": "yes", - "fill_count": 1, - "observed_at": "2026-07-26T21:59:30Z", - } - try: - wrapper = reader.settlement_reconciliation_witness(position) - finally: - provider.close() - - assert wrapper is not None - assert wrapper["body"]["position_absent"] is True - assert wrapper["body"]["market_result"] == "yes" - assert wrapper["body"]["settlement_fee_cents"] == 2 - assert position_reads == 2 diff --git a/tests/test_dumbmoney_lineage.py b/tests/test_dumbmoney_lineage.py deleted file mode 100644 index f645e5f2..00000000 --- a/tests/test_dumbmoney_lineage.py +++ /dev/null @@ -1,573 +0,0 @@ -from __future__ import annotations - -import base64 -import hashlib -import json -from dataclasses import replace -from datetime import datetime, timedelta, timezone -from urllib.parse import parse_qs, urlsplit - -import pytest -from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey - -from live_firewall.dumbmoney_capital import ( - CAPITAL_ENVELOPE_SCHEMA, - SIGNED_ENVELOPE_SCHEMA, - verify_signed_capital_envelope, -) -from live_firewall.dumbmoney_lineage import ( - ALPHA_PASSPORT_SCHEMA, - CONTRACT_RESOLUTION_CHECKPOINT_SCHEMA, - CONTRACT_RESOLUTION_SCHEMA, - PROMOTION_CERTIFICATE_SCHEMA, - ContractResolutionResponse, - CoreAuthorityContractResolver, - LineageResolutionError, -) -from live_firewall.operational_journal import canonical_json, sha256_json - - -NOW = datetime(2026, 7, 26, 22, 30, 0, tzinfo=timezone.utc) -ACCOUNT_HASH = "c" * 64 -STRATEGY_HASH = "a" * 64 -INSTRUMENT = "event_contract:KXTEST-26JUL" -ZERO_DIGEST = "0" * 64 - - -def _z(value: datetime) -> str: - return value.astimezone(timezone.utc).isoformat().replace("+00:00", "Z") - - -def _sign( - private_key: Ed25519PrivateKey, - body: dict, - *, - source_id: str, - source_sequence: int = 1, - not_before: datetime = NOW - timedelta(seconds=10), - expires_at: datetime = NOW + timedelta(minutes=10), -) -> dict: - public = private_key.public_key().public_bytes_raw() - identity = { - "schema": SIGNED_ENVELOPE_SCHEMA, - "source_id": source_id, - "source_sequence": source_sequence, - "correlation_id": "dummy-lineage-fixture", - "causation_id": None, - "nonce": f"{source_id}-nonce-{source_sequence}", - "not_before": _z(not_before), - "expires_at": _z(expires_at), - "body_schema": body["schema"], - "body_digest": sha256_json(body), - "body": body, - "signature_algorithm": "Ed25519", - "signer_key_id": hashlib.sha256(public).hexdigest(), - } - wrapper = {**identity, "event_id": sha256_json(identity)} - wrapper["signature"] = ( - base64.urlsafe_b64encode( - private_key.sign(canonical_json(wrapper).encode()) - ) - .decode() - .rstrip("=") - ) - return wrapper - - -def _passport() -> dict: - return { - "schema": ALPHA_PASSPORT_SCHEMA, - "passport_id": "passport-dummy-1", - "strategy_lineage_id": "lineage-dummy-1", - "venue": "dummy_kalshi", - "strategy_hash": STRATEGY_HASH, - "artifact_hashes": ["1" * 64], - "evidence_verdict_hashes": ["2" * 64], - "intended_instruments": [INSTRUMENT], - "maximum_loss_cents": 100, - "evidence_class": "FORWARD", - "created_at": _z(NOW - timedelta(days=1)), - "expires_at": _z(NOW + timedelta(days=1)), - } - - -def _promotion(passport_digest: str, *, policy_epoch: int = 1) -> dict: - return { - "schema": PROMOTION_CERTIFICATE_SCHEMA, - "certificate_id": "promotion-dummy-1", - "passport_digest": passport_digest, - "verdict_digests": ["3" * 64], - "stage": "EXPLORATORY_LIVE", - "venue": "dummy_kalshi", - "instruments": [INSTRUMENT], - "maximum_loss_cents": 100, - "rollback_triggers": ["AMBIGUOUS_OUTCOME", "KILL_ACTIVE"], - "policy_epoch": policy_epoch, - "not_before": _z(NOW - timedelta(days=1)), - "expires_at": _z(NOW + timedelta(days=1)), - } - - -def _capital(passport_digest: str, promotion_digest: str) -> dict: - return { - "schema": CAPITAL_ENVELOPE_SCHEMA, - "envelope_id": "e" * 64, - "mandate_id": "d" * 64, - "venue": "dummy_kalshi", - "account_hash": ACCOUNT_HASH, - "strategy_hashes": [STRATEGY_HASH], - "passport_hashes": [passport_digest], - "promotion_hashes": [promotion_digest], - "authorized_instruments": [INSTRUMENT], - "authorized_mode": "LIVE", - "max_order_risk_cents": 100, - "max_open_risk_cents": 500, - "max_correlated_risk_cents": 300, - "max_daily_loss_cents": 300, - "max_open_orders": 5, - "fencing_generation": 7, - "policy_epoch": 1, - "not_before": _z(NOW - timedelta(seconds=5)), - "expires_at": _z(NOW + timedelta(seconds=60)), - } - - -def _proof(envelope: dict, *, sequence: int) -> dict: - received = NOW - timedelta(seconds=1) - observed = max( - received, - datetime.fromisoformat( - envelope["not_before"].replace("Z", "+00:00") - ), - ) - proof = { - "schema": "dumbmoney.ledger-event-proof.v1", - "global_sequence": sequence, - "event_id": envelope["event_id"], - "source_id": envelope["source_id"], - "source_sequence": envelope["source_sequence"], - "signer_key_id": envelope["signer_key_id"], - "nonce": envelope["nonce"], - "event_schema": envelope["body_schema"], - "observed_at": _z(observed), - "received_at": _z(received), - "correlation_id": envelope["correlation_id"], - "causation_id": envelope["causation_id"], - "payload_digest": envelope["body_digest"], - "previous_source_digest": ZERO_DIGEST, - "previous_global_digest": ( - ZERO_DIGEST if sequence == 1 else "9" * 64 - ), - } - proof["event_digest"] = sha256_json( - { - key: value - for key, value in proof.items() - if key != "schema" - } - ) - return proof - - -def _resolution( - core: Ed25519PrivateKey, - envelope: dict, - *, - nonce: str, - capital_digest: str, - sequence: int, - authority_state: dict, -) -> dict: - checkpoint = { - "schema": CONTRACT_RESOLUTION_CHECKPOINT_SCHEMA, - "cell_id": "dummy_kalshi", - "request_nonce": nonce, - "requested_body_digest": envelope["body_digest"], - "capital_envelope_digest": capital_digest, - "fencing_generation": 7, - "observed_at": _z(NOW), - "contract_schema": envelope["body_schema"], - "transport_window_current": True, - "body_window_current": True, - "eligible_live_input": True, - "authority_state": authority_state, - "ledger_proof": _proof(envelope, sequence=sequence), - "envelope": envelope, - } - public = core.public_key().public_bytes_raw() - signature = core.sign(canonical_json(checkpoint).encode()) - return { - "schema": CONTRACT_RESOLUTION_SCHEMA, - **{ - key: value - for key, value in checkpoint.items() - if key != "schema" - }, - "checkpoint": checkpoint, - "checkpoint_signature": { - "algorithm": "Ed25519", - "signer_key_id": hashlib.sha256(public).hexdigest(), - "signature": base64.urlsafe_b64encode(signature) - .decode() - .rstrip("="), - }, - } - - -class _Transport: - def __init__( - self, - core: Ed25519PrivateKey, - capital_digest: str, - envelopes: dict[str, dict], - authority_state: dict, - *, - mutate=None, - after_call=None, - resign_mutation: bool = False, - ) -> None: - self.core = core - self.capital_digest = capital_digest - self.envelopes = envelopes - self.authority_state = authority_state - self.mutate = mutate - self.after_call = after_call - self.resign_mutation = resign_mutation - self.requests: list[tuple[str, dict[str, str]]] = [] - - def __call__(self, path: str, headers) -> ContractResolutionResponse: - self.requests.append((path, dict(headers))) - parsed = urlsplit(path) - query = parse_qs(parsed.query) - assert query["capital_envelope_digest"] == [self.capital_digest] - digest = parsed.path.rsplit("/", 1)[-1] - envelope = self.envelopes[digest] - response = _resolution( - self.core, - envelope, - nonce=query["request_nonce"][0], - capital_digest=self.capital_digest, - sequence=( - 1 - if envelope["body_schema"] == ALPHA_PASSPORT_SCHEMA - else 2 - ), - authority_state=self.authority_state, - ) - if self.mutate is not None: - response = self.mutate(response) - if self.resign_mutation: - checkpoint = { - "schema": CONTRACT_RESOLUTION_CHECKPOINT_SCHEMA, - **{ - key: value - for key, value in response.items() - if key - not in { - "schema", - "checkpoint", - "checkpoint_signature", - } - }, - } - public = self.core.public_key().public_bytes_raw() - response["checkpoint"] = checkpoint - response["checkpoint_signature"] = { - "algorithm": "Ed25519", - "signer_key_id": hashlib.sha256(public).hexdigest(), - "signature": base64.urlsafe_b64encode( - self.core.sign(canonical_json(checkpoint).encode()) - ) - .decode() - .rstrip("="), - } - if self.after_call is not None: - self.after_call() - return ContractResolutionResponse( - status_code=200, - body=json.dumps(response, separators=(",", ":")).encode(), - ) - - -def _runtime( - *, - promotion_role: str = "promoter", - mutate=None, - clock=None, - resign_mutation: bool = False, -): - core = Ed25519PrivateKey.generate() - research = Ed25519PrivateKey.generate() - promoter = Ed25519PrivateKey.generate() - evaluator_integrity = Ed25519PrivateKey.generate() - evaluator_statistics = Ed25519PrivateKey.generate() - passport = _sign(research, _passport(), source_id="research") - promotion_key = research if promotion_role == "research" else promoter - promotion = _sign( - promotion_key, - _promotion(passport["body_digest"]), - source_id="promoter", - ) - capital_wrapper = _sign( - core, - _capital(passport["body_digest"], promotion["body_digest"]), - source_id="dumbmoney-core", - not_before=NOW - timedelta(seconds=5), - expires_at=NOW + timedelta(seconds=60), - ) - core_public = core.public_key().public_bytes_raw() - capital = verify_signed_capital_envelope( - capital_wrapper, - trusted_public_keys={ - hashlib.sha256(core_public).hexdigest(): core_public - }, - expected_venue="dummy_kalshi", - expected_account_hash=ACCOUNT_HASH, - now=NOW, - ) - capital = replace( - capital, - ledger_event_digest="c" * 64, - ledger_global_sequence=3, - ) - evaluator_publics = [ - evaluator_integrity.public_key().public_bytes_raw(), - evaluator_statistics.public_key().public_bytes_raw(), - ] - authority_state = { - "schema": "dumbmoney.cell-authority-state.v1", - "evaluated_at": _z(NOW), - "authority_valid_until": _z(NOW + timedelta(seconds=30)), - "policy_epoch": capital.policy_epoch, - "mandate_id": capital.body["mandate_id"], - "mandate_event_digest": "4" * 64, - "kill_clear": True, - "kill_generation": 1, - "kill_event_digest": "5" * 64, - "desired_mode": "LIVE", - "desired_mode_revision": 1, - "desired_mode_event_digest": "6" * 64, - "capital_envelope_digest": sha256_json(capital.body), - "capital_event_digest": capital.ledger_event_digest, - "fencing_generation": capital.fencing_generation, - "strategy_hash": STRATEGY_HASH, - "passport_digest": passport["body_digest"], - "passport_event_digest": _proof( - passport, - sequence=1, - )["event_digest"], - "promotion_digest": promotion["body_digest"], - "promotion_event_digest": _proof( - promotion, - sequence=2, - )["event_digest"], - "verdicts": [ - { - "verdict_digest": "7" * 64, - "verdict_event_digest": "8" * 64, - "verdict_id": "verdict-integrity-1", - "court": "integrity", - "decision": "PASS", - "signer_key_id": hashlib.sha256( - evaluator_publics[0] - ).hexdigest(), - "evaluated_at": _z(NOW - timedelta(seconds=5)), - "expires_at": _z(NOW + timedelta(minutes=5)), - "transport_expires_at": _z(NOW + timedelta(minutes=5)), - }, - { - "verdict_digest": "9" * 64, - "verdict_event_digest": "a" * 64, - "verdict_id": "verdict-statistics-1", - "court": "statistics", - "decision": "PASS", - "signer_key_id": hashlib.sha256( - evaluator_publics[1] - ).hexdigest(), - "evaluated_at": _z(NOW - timedelta(seconds=4)), - "expires_at": _z(NOW + timedelta(minutes=5)), - "transport_expires_at": _z(NOW + timedelta(minutes=5)), - }, - ], - "ledger_head_sequence": 4, - "ledger_head_digest": "b" * 64, - } - transport = _Transport( - core, - sha256_json(capital.body), - { - passport["body_digest"]: passport, - promotion["body_digest"]: promotion, - }, - authority_state, - mutate=mutate, - after_call=( - None if clock is None else clock.get("after_call") - ), - resign_mutation=resign_mutation, - ) - research_public = research.public_key().public_bytes_raw() - promoter_public = promoter.public_key().public_bytes_raw() - resolver = CoreAuthorityContractResolver( - transport=transport, - cell_token_provider=lambda: "t" * 64, - trusted_core_public_keys={ - hashlib.sha256(core_public).hexdigest(): core_public - }, - trusted_research_public_keys={ - hashlib.sha256(research_public).hexdigest(): research_public - }, - trusted_promoter_public_keys={ - hashlib.sha256(promoter_public).hexdigest(): promoter_public - }, - trusted_evaluator_public_keys={ - hashlib.sha256(public).hexdigest(): public - for public in evaluator_publics - }, - now_fn=(lambda: NOW) if clock is None else clock["now"], - ) - return resolver, capital, transport - - -def test_nonce_fence_and_role_bound_lineage_resolves() -> None: - resolver, capital, transport = _runtime() - - binding = resolver.resolve_lineage( - capital=capital, - strategy_hash=STRATEGY_HASH, - passport_hash=capital.passport_hashes[0], - promotion_hash=capital.promotion_hashes[0], - authorized_instrument=INSTRUMENT, - ) - - assert binding.capital_body_digest == sha256_json(capital.body) - assert binding.capital_fencing_generation == 7 - assert binding.authorized_instrument == INSTRUMENT - assert len(transport.requests) == 2 - nonces = [ - parse_qs(urlsplit(path).query)["request_nonce"][0] - for path, _ in transport.requests - ] - assert len(set(nonces)) == 2 - assert all( - headers["Authorization"] == f"Bearer {'t' * 64}" - for _, headers in transport.requests - ) - - -def test_wrong_role_promotion_is_rejected() -> None: - resolver, capital, _ = _runtime(promotion_role="research") - - with pytest.raises(LineageResolutionError, match="signer"): - resolver.resolve_lineage( - capital=capital, - strategy_hash=STRATEGY_HASH, - passport_hash=capital.passport_hashes[0], - promotion_hash=capital.promotion_hashes[0], - authorized_instrument=INSTRUMENT, - ) - - -def test_unsigned_capital_digest_transplant_is_rejected() -> None: - def mutate(response: dict) -> dict: - response["capital_envelope_digest"] = "8" * 64 - return response - - resolver, capital, _ = _runtime(mutate=mutate) - - with pytest.raises(LineageResolutionError, match="checkpoint"): - resolver.resolve_lineage( - capital=capital, - strategy_hash=STRATEGY_HASH, - passport_hash=capital.passport_hashes[0], - promotion_hash=capital.promotion_hashes[0], - authorized_instrument=INSTRUMENT, - ) - - -def test_slow_transport_cannot_return_expired_resolution() -> None: - state = {"value": NOW} - - def after_call() -> None: - state["value"] = NOW + timedelta(minutes=2) - - resolver, capital, _ = _runtime( - clock={ - "now": lambda: state["value"], - "after_call": after_call, - } - ) - - with pytest.raises(LineageResolutionError, match="stale"): - resolver.resolve_lineage( - capital=capital, - strategy_hash=STRATEGY_HASH, - passport_hash=capital.passport_hashes[0], - promotion_hash=capital.promotion_hashes[0], - authorized_instrument=INSTRUMENT, - ) - - -def test_core_signed_authority_rejects_unsealed_evaluator() -> None: - def mutate(response: dict) -> dict: - response["authority_state"]["verdicts"][0][ - "signer_key_id" - ] = "f" * 64 - return response - - resolver, capital, _ = _runtime( - mutate=mutate, - resign_mutation=True, - ) - - with pytest.raises(LineageResolutionError, match="signer is not sealed"): - resolver.resolve_lineage( - capital=capital, - strategy_hash=STRATEGY_HASH, - passport_hash=capital.passport_hashes[0], - promotion_hash=capital.promotion_hashes[0], - authorized_instrument=INSTRUMENT, - ) - - -def test_passport_and_promotion_require_one_authority_state() -> None: - calls = 0 - - def mutate(response: dict) -> dict: - nonlocal calls - calls += 1 - if calls == 2: - response["authority_state"]["kill_generation"] = 2 - return response - - resolver, capital, _ = _runtime( - mutate=mutate, - resign_mutation=True, - ) - - with pytest.raises(LineageResolutionError, match="one authority state"): - resolver.resolve_lineage( - capital=capital, - strategy_hash=STRATEGY_HASH, - passport_hash=capital.passport_hashes[0], - promotion_hash=capital.promotion_hashes[0], - authorized_instrument=INSTRUMENT, - ) - - -def test_capital_requires_authenticated_core_ledger_event() -> None: - resolver, capital, _ = _runtime() - unbound = replace( - capital, - ledger_event_digest=None, - ledger_global_sequence=None, - ) - - with pytest.raises(LineageResolutionError, match="ledger binding"): - resolver.resolve_lineage( - capital=unbound, - strategy_hash=STRATEGY_HASH, - passport_hash=capital.passport_hashes[0], - promotion_hash=capital.promotion_hashes[0], - authorized_instrument=INSTRUMENT, - ) diff --git a/tests/test_dumbmoney_windows_service.py b/tests/test_dumbmoney_windows_service.py deleted file mode 100644 index d2e14f2e..00000000 --- a/tests/test_dumbmoney_windows_service.py +++ /dev/null @@ -1,692 +0,0 @@ -from __future__ import annotations - -import base64 -import hashlib -import json -import sqlite3 -from datetime import datetime, timezone -from pathlib import Path - -import pytest -from cryptography.hazmat.primitives import serialization -from cryptography.hazmat.primitives.asymmetric import rsa -from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey - -from autonomy.executor import Executor -from autonomy.ontology import SessionMode -from live_firewall.dumbmoney_capital import verify_signed_envelope -from live_firewall.dumbmoney_command_feed import CommandFeedPollResult -from live_firewall.dumbmoney_windows_service import ( - CELL_TOKEN_TARGET_REF, - CONFIG_RELATIVE_PATH, - CONFIG_SCHEMA, - CORE_ENDPOINT_REF, - CORE_READINESS_RELATIVE_PATH, - DATA_ROOT_RELATIVE_PATH, - KALSHI_KEY_ID_TARGET_REF, - KALSHI_PRIVATE_KEY_TARGET_REF, - READINESS_KEY_TARGET_REF, - READINESS_REF, - READINESS_RELATIVE_PATH, - READINESS_SCHEMA, - SERVICE_NAME, - START_MODE, - CoreEndpoint, - DumbMoneyDummyKalshiService, - DumbMoneyWindowsServiceError, - DummyKalshiRunnerConfig, - RunnerSecrets, - kalshi_account_hash, - load_runner_config, - load_secrets, -) - - -NOW = datetime(2026, 7, 26, 22, 0, 0, tzinfo=timezone.utc) - - -def _hash(label: str) -> str: - return hashlib.sha256(label.encode("utf-8")).hexdigest() - - -def _key(seed: int) -> tuple[str, bytes, str]: - private = Ed25519PrivateKey.from_private_bytes(bytes([seed]) * 32) - public = private.public_key().public_bytes_raw() - return ( - hashlib.sha256(public).hexdigest(), - public, - base64.urlsafe_b64encode(public).decode("ascii").rstrip("="), - ) - - -def _config( - tmp_path: Path, - *, - readiness_private: Ed25519PrivateKey, - key_id: str = "kalshi-fixture-key", -) -> DummyKalshiRunnerConfig: - core_id, core, _ = _key(1) - operator_id, operator, _ = _key(2) - promoter_id, promoter, _ = _key(3) - research_id, research, _ = _key(4) - evaluator_id, evaluator, _ = _key(6) - readiness_id = hashlib.sha256( - readiness_private.public_key().public_bytes_raw() - ).hexdigest() - return DummyKalshiRunnerConfig( - release_id="release-fixture-1", - core_readiness_path=tmp_path / "core-readiness.json", - data_root=tmp_path / "data", - readiness_path=tmp_path / "readiness.json", - core_public_keys={core_id: core}, - operator_public_keys={operator_id: operator}, - promoter_public_keys={promoter_id: promoter}, - research_public_keys={research_id: research}, - evaluator_public_keys={evaluator_id: evaluator}, - expected_account_hash=kalshi_account_hash(key_id, 0), - kalshi_subaccount_number=0, - fund_lock_sha256=_hash("fund-lock"), - service_manifest_sha256=_hash("manifest"), - role_public_keys_sha256=_hash("roles"), - core_runner_config_sha256=_hash("core-config"), - risk_policy_sha256=_hash("risk"), - readiness_signer_public_key_sha256=readiness_id, - poll_interval_seconds=5, - readiness_ttl_seconds=30, - broker_truth_max_age_seconds=30, - config_sha256=_hash("runner-config"), - ) - - -def _public_config_payload( - program_data: Path, - *, - readiness_private: Ed25519PrivateKey, - key_id: str, -) -> dict: - core_id, _, core = _key(1) - operator_id, _, operator = _key(2) - promoter_id, _, promoter = _key(3) - research_id, _, research = _key(4) - evaluator_id, _, evaluator = _key(6) - return { - "schema": CONFIG_SCHEMA, - "service_name": SERVICE_NAME, - "release_id": "release-fixture-1", - "core_endpoint_ref": CORE_ENDPOINT_REF, - "core_readiness_path": str( - (program_data / CORE_READINESS_RELATIVE_PATH).resolve() - ), - "core_cell_token_target": CELL_TOKEN_TARGET_REF, - "kalshi_key_id_target": KALSHI_KEY_ID_TARGET_REF, - "kalshi_private_key_target": KALSHI_PRIVATE_KEY_TARGET_REF, - "readiness_signing_key_target": READINESS_KEY_TARGET_REF, - "start_mode": START_MODE, - "data_root": str((program_data / DATA_ROOT_RELATIVE_PATH).resolve()), - "readiness_ref": READINESS_REF, - "readiness_path": str( - (program_data / READINESS_RELATIVE_PATH).resolve() - ), - "core_public_keys_base64url": {core_id: core}, - "operator_public_keys_base64url": {operator_id: operator}, - "promoter_public_keys_base64url": {promoter_id: promoter}, - "research_public_keys_base64url": {research_id: research}, - "evaluator_public_keys_base64url": {evaluator_id: evaluator}, - "expected_account_hash": kalshi_account_hash(key_id, 0), - "kalshi_subaccount_number": 0, - "fund_lock_sha256": _hash("fund-lock"), - "service_manifest_sha256": _hash("manifest"), - "role_public_keys_sha256": _hash("roles"), - "core_runner_config_sha256": _hash("core-config"), - "risk_policy_sha256": _hash("risk"), - "readiness_signer_public_key_sha256": hashlib.sha256( - readiness_private.public_key().public_bytes_raw() - ).hexdigest(), - "poll_interval_seconds": 5, - "readiness_ttl_seconds": 30, - "broker_truth_max_age_seconds": 30, - } - - -class _Credentials: - def __init__(self, values: dict[str, bytes]) -> None: - self.values = values - self.targets: list[str] = [] - - def read_bytes(self, target: str) -> bytes: - self.targets.append(target) - return self.values[target] - - -def test_config_is_raw_byte_pinned_and_secrets_use_only_four_targets( - tmp_path: Path, -) -> None: - program_data = tmp_path / "ProgramData" - readiness = Ed25519PrivateKey.from_private_bytes(bytes([9]) * 32) - key_id = "kalshi-fixture-key" - payload = _public_config_payload( - program_data, - readiness_private=readiness, - key_id=key_id, - ) - raw = json.dumps(payload, separators=(",", ":"), sort_keys=True).encode() - config_path = program_data / CONFIG_RELATIVE_PATH - config_path.parent.mkdir(parents=True) - config_path.write_bytes(raw) - config = load_runner_config( - config_path, - hashlib.sha256(raw).hexdigest(), - program_data, - ) - - rsa_private = rsa.generate_private_key( - public_exponent=65537, - key_size=2048, - ) - pem = rsa_private.private_bytes( - serialization.Encoding.PEM, - serialization.PrivateFormat.PKCS8, - serialization.NoEncryption(), - ) - provider = _Credentials( - { - "DumbMoney/DummyCellToken": b"t" * 64, - "DumbMoney/KalshiApiKeyId": key_id.encode(), - "DumbMoney/KalshiPrivateKeyPem": pem, - "DumbMoney/DummyReadinessEd25519": bytes([9]) * 32, - } - ) - secrets = load_secrets(provider, config) - - assert secrets.cell_token == "t" * 64 - assert secrets.kalshi_key_id == key_id - assert provider.targets == [ - "DumbMoney/DummyCellToken", - "DumbMoney/KalshiApiKeyId", - "DumbMoney/KalshiPrivateKeyPem", - "DumbMoney/DummyReadinessEd25519", - ] - - -class _NoNetworkTransport: - def __init__(self) -> None: - self.calls = 0 - self.endpoint: CoreEndpoint | None = None - - def set_endpoint(self, endpoint: CoreEndpoint) -> None: - self.endpoint = endpoint - - def liveness(self) -> None: - self.calls += 1 - - def contract_get(self, *_args, **_kwargs): - raise AssertionError("contract transport must not run during setup") - - def command_get(self, *_args, **_kwargs): - raise AssertionError("command transport must not run during setup") - - def journal_anchor_post(self, *_args, **_kwargs): - raise AssertionError("anchor transport must not run during setup") - - def close(self) -> None: - return - - -class _BrokerTruth: - def __init__(self, snapshot: dict) -> None: - self.value = snapshot - self.calls = 0 - - def snapshot(self) -> dict: - self.calls += 1 - return dict(self.value) - - -def _secrets(readiness: Ed25519PrivateKey) -> RunnerSecrets: - return RunnerSecrets( - cell_token="t" * 64, - kalshi_key_id="kalshi-fixture-key", - kalshi_private_key_pem=b"unused-in-unit-service", - readiness_private_key=readiness, - ) - - -def test_startup_is_network_silent_and_readiness_is_signed_blocked( - tmp_path: Path, -) -> None: - readiness = Ed25519PrivateKey.from_private_bytes(bytes([9]) * 32) - config = _config(tmp_path, readiness_private=readiness) - transport = _NoNetworkTransport() - broker = _BrokerTruth({}) - service = DumbMoneyDummyKalshiService( - config, - _secrets(readiness), - core_transport=transport, # type: ignore[arg-type] - broker_truth=broker, - clock=lambda: NOW, - ) - try: - service.start() - envelope = json.loads(config.readiness_path.read_text()) - verified = verify_signed_envelope( - envelope, - trusted_public_keys={ - config.readiness_signer_public_key_sha256: ( - readiness.public_key().public_bytes_raw() - ) - }, - now=NOW, - expected_body_schema=READINESS_SCHEMA, - ) - - assert transport.calls == 0 - assert broker.calls == 0 - assert verified.body["authority"] == { - "broker": "KALSHI", - "mode": START_MODE, - "execution_enabled": False, - } - assert verified.body["health"]["status"] == "BLOCKED" - finally: - service.close() - - -def test_service_components_use_sqlite_wal_journals_and_close_them( - tmp_path: Path, -) -> None: - readiness = Ed25519PrivateKey.from_private_bytes(bytes([9]) * 32) - config = _config(tmp_path, readiness_private=readiness) - transport = _NoNetworkTransport() - service = DumbMoneyDummyKalshiService( - config, - _secrets(readiness), - core_transport=transport, # type: ignore[arg-type] - broker_truth=_BrokerTruth({}), - clock=lambda: NOW, - ) - service.start() - try: - service._initialize_components() - capital_path = config.data_root / "capital-operational.db" - command_path = config.data_root / "command-feed.db" - assert capital_path.is_file() - assert command_path.is_file() - assert not (config.data_root / "capital-operational.jsonl").exists() - assert not (config.data_root / "command-feed.jsonl").exists() - - for path in (capital_path, command_path): - with sqlite3.connect(path) as connection: - assert connection.execute( - "PRAGMA journal_mode" - ).fetchone()[0] == "wal" - assert connection.execute( - "SELECT event_count FROM journal_metadata " - "WHERE singleton = 1" - ).fetchone() == (0,) - finally: - service.close() - - assert service._capital_journal is None - assert service._command_journal is None - - -def test_legacy_live_executor_cannot_construct_firewall_without_dumbmoney( - tmp_path: Path, -) -> None: - executor = Executor( - SessionMode.LIVE, - session_path=tmp_path / "session.json", - kill_path=tmp_path / "KILL", - capital_envelope_adapter=None, - ) - - with pytest.raises(RuntimeError, match="mandatory for LIVE"): - executor._make_firewall() - - -class _CommandFeed: - def poll_once(self) -> CommandFeedPollResult: - return CommandFeedPollResult( - page_accepted=True, - cursor_sequence=1, - cursor_digest="1" * 64, - commands_applied=1, - required_action="APPLY_SIGNED_CONTROLS", - submission_allowed=True, - reason="fixture current", - ) - - def submission_allowed(self) -> bool: - return True - - -class _CapitalAdapter: - def __init__(self) -> None: - self.receipts: list[dict] = [] - - def record_broker_bootstrap(self, receipt: dict) -> None: - self.receipts.append(receipt) - - -class _JournalHead: - def head(self) -> tuple[int, str]: - return 0, "0" * 64 - - def close(self) -> None: - return - - -class _ExposureHead: - def anchor_head(self) -> tuple[int, str]: - return 0, "0" * 64 - - -class _JournalAnchorClient: - def __init__(self) -> None: - self.calls: list[dict] = [] - - def anchor(self, **kwargs) -> None: - self.calls.append(kwargs) - - -class _RejectingJournalAnchorClient: - def anchor(self, **_kwargs) -> None: - raise RuntimeError("Core rejected rolled-back journal") - - -def _install_anchor_fixtures( - service: DumbMoneyDummyKalshiService, -) -> _JournalAnchorClient: - client = _JournalAnchorClient() - service._capital_journal = _JournalHead() # type: ignore[assignment] - service._command_journal = _JournalHead() # type: ignore[assignment] - service._exposure_tracker = _ExposureHead() # type: ignore[assignment] - service._journal_anchor_client = client # type: ignore[assignment] - return client - - -class _ReconciliationSweeper: - def __init__( - self, - *, - unresolved_reservations: int, - unresolved_positions: int, - ) -> None: - self.unresolved_reservations = unresolved_reservations - self.unresolved_positions = unresolved_positions - self.calls = 0 - - def run_once(self) -> dict: - self.calls += 1 - return { - "unresolved_reservations": self.unresolved_reservations, - "unresolved_positions": self.unresolved_positions, - } - - -def test_anchor_rejection_blocks_before_broker_contact( - tmp_path: Path, - monkeypatch, -) -> None: - readiness = Ed25519PrivateKey.from_private_bytes(bytes([9]) * 32) - config = _config(tmp_path, readiness_private=readiness) - transport = _NoNetworkTransport() - broker = _BrokerTruth({}) - service = DumbMoneyDummyKalshiService( - config, - _secrets(readiness), - core_transport=transport, # type: ignore[arg-type] - broker_truth=broker, - journal_anchor_client=( # type: ignore[arg-type] - _RejectingJournalAnchorClient() - ), - clock=lambda: NOW, - ) - service._components_ready = True - service._capital_adapter = _CapitalAdapter() # type: ignore[assignment] - service._command_feed = _CommandFeed() # type: ignore[assignment] - service._capital_journal = _JournalHead() # type: ignore[assignment] - service._command_journal = _JournalHead() # type: ignore[assignment] - service._exposure_tracker = _ExposureHead() # type: ignore[assignment] - monkeypatch.setattr( - "live_firewall.dumbmoney_windows_service._core_endpoint_from_readiness", - lambda *_args, **_kwargs: CoreEndpoint( - base_url="http://127.0.0.1:8765", - instance_id="00000000-0000-0000-0000-000000000001", - observed_at="2026-07-26T22:00:00Z", - valid_until="2026-07-26T22:01:00Z", - ), - ) - try: - service.start() - with pytest.raises( - RuntimeError, - match="rolled-back journal", - ): - service.run_once() - state = service.state() - assert broker.calls == 0 - assert state.health_status == "BLOCKED" - assert state.rollback_anchor_current is False - assert state.execution_enabled is False - finally: - service.close() - - -def test_pending_restart_reconciliation_blocks_otherwise_flat_book( - tmp_path: Path, - monkeypatch, -) -> None: - readiness = Ed25519PrivateKey.from_private_bytes(bytes([9]) * 32) - config = _config(tmp_path, readiness_private=readiness) - transport = _NoNetworkTransport() - broker = _BrokerTruth({ - "schema": "dummy.kalshi-broker-truth.v1", - "venue": "dummy_kalshi", - "account_hash": config.expected_account_hash, - "subaccount_number": 0, - "observed_at": "2026-07-26T22:00:00Z", - "broker_snapshot_sha256": _hash("flat-with-pending"), - "flat_book_observed": True, - "total_exposure_cents": 0, - "open_order_count": 0, - "market_exposure_cents": {}, - "correlated_exposure_cents": {}, - "unresolved_open_orders": 0, - "unresolved_positions": 0, - }) - sweeper = _ReconciliationSweeper( - unresolved_reservations=1, - unresolved_positions=0, - ) - service = DumbMoneyDummyKalshiService( - config, - _secrets(readiness), - core_transport=transport, # type: ignore[arg-type] - broker_truth=broker, - reconciliation_sweeper=sweeper, # type: ignore[arg-type] - clock=lambda: NOW, - ) - service._components_ready = True - service._capital_adapter = _CapitalAdapter() # type: ignore[assignment] - service._command_feed = _CommandFeed() # type: ignore[assignment] - anchors = _install_anchor_fixtures(service) - monkeypatch.setattr( - "live_firewall.dumbmoney_windows_service._core_endpoint_from_readiness", - lambda *_args, **_kwargs: CoreEndpoint( - base_url="http://127.0.0.1:8765", - instance_id="00000000-0000-0000-0000-000000000001", - observed_at="2026-07-26T22:00:00Z", - valid_until="2026-07-26T22:01:00Z", - ), - ) - try: - service.start() - result = service.run_once() - state = service.state() - - assert result["status"] == "RECONCILIATION_BLOCKED" - assert state.reason == "UNRESOLVED_BROKER_ORDERS_OR_POSITIONS" - assert state.unresolved_open_orders == 1 - assert state.execution_enabled is False - assert sweeper.calls == 1 - assert len(anchors.calls) == 6 - finally: - service.close() - - -def test_unresolved_broker_book_stays_reconciliation_only( - tmp_path: Path, - monkeypatch, -) -> None: - readiness = Ed25519PrivateKey.from_private_bytes(bytes([9]) * 32) - config = _config(tmp_path, readiness_private=readiness) - transport = _NoNetworkTransport() - snapshot_body = { - "schema": "dummy.kalshi-broker-truth.v1", - "venue": "dummy_kalshi", - "account_hash": config.expected_account_hash, - "subaccount_number": 0, - "observed_at": "2026-07-26T22:00:00Z", - "broker_snapshot_sha256": _hash("broker-snapshot"), - "flat_book_observed": False, - "total_exposure_cents": 100, - "open_order_count": 1, - "market_exposure_cents": {"KXTEST": 100}, - "correlated_exposure_cents": {"KXTEST": 100}, - "unresolved_open_orders": 1, - "unresolved_positions": 1, - } - broker = _BrokerTruth(snapshot_body) - service = DumbMoneyDummyKalshiService( - config, - _secrets(readiness), - core_transport=transport, # type: ignore[arg-type] - broker_truth=broker, - execution_cycle=lambda **_kwargs: {"orders_submitted": 1}, - clock=lambda: NOW, - ) - adapter = _CapitalAdapter() - service._components_ready = True - service._capital_adapter = adapter # type: ignore[assignment] - service._command_feed = _CommandFeed() # type: ignore[assignment] - anchors = _install_anchor_fixtures(service) - monkeypatch.setattr( - "live_firewall.dumbmoney_windows_service._core_endpoint_from_readiness", - lambda *_args, **_kwargs: CoreEndpoint( - base_url="http://127.0.0.1:8765", - instance_id="00000000-0000-0000-0000-000000000001", - observed_at="2026-07-26T22:00:00Z", - valid_until="2026-07-26T22:01:00Z", - ), - ) - try: - service.start() - result = service.run_once() - state = service.state() - - assert result["status"] == "RECONCILIATION_BLOCKED" - assert state.mode == START_MODE - assert state.execution_enabled is False - assert state.reconciled_once is False - assert state.unresolved_open_orders == 1 - assert state.unresolved_positions == 1 - assert len(adapter.receipts) == 1 - assert len(anchors.calls) == 6 - finally: - service.close() - - -def test_second_pass_blocked_cycle_cannot_publish_ready( - tmp_path: Path, - monkeypatch, -) -> None: - readiness = Ed25519PrivateKey.from_private_bytes(bytes([9]) * 32) - config = _config(tmp_path, readiness_private=readiness) - transport = _NoNetworkTransport() - broker = _BrokerTruth({ - "schema": "dummy.kalshi-broker-truth.v1", - "venue": "dummy_kalshi", - "account_hash": config.expected_account_hash, - "subaccount_number": 0, - "observed_at": "2026-07-26T22:00:00Z", - "broker_snapshot_sha256": _hash("flat-broker-snapshot"), - "flat_book_observed": True, - "total_exposure_cents": 0, - "open_order_count": 0, - "market_exposure_cents": {}, - "correlated_exposure_cents": {}, - "unresolved_open_orders": 0, - "unresolved_positions": 0, - }) - cycle_calls: list[dict] = [] - - def blocked_cycle(**kwargs): - cycle_calls.append(kwargs) - return { - "schema": "dummy.dumbmoney-execution-cycle.v1", - "status": "BLOCKED", - "broker_contacted": False, - "orders_submitted": 0, - "broker_snapshot_sha256": _hash("flat-broker-snapshot"), - } - - service = DumbMoneyDummyKalshiService( - config, - _secrets(readiness), - core_transport=transport, # type: ignore[arg-type] - broker_truth=broker, - execution_cycle=blocked_cycle, - clock=lambda: NOW, - ) - adapter = _CapitalAdapter() - service._components_ready = True - service._capital_adapter = adapter # type: ignore[assignment] - service._command_feed = _CommandFeed() # type: ignore[assignment] - anchors = _install_anchor_fixtures(service) - monkeypatch.setattr( - "live_firewall.dumbmoney_windows_service._core_endpoint_from_readiness", - lambda *_args, **_kwargs: CoreEndpoint( - base_url="http://127.0.0.1:8765", - instance_id="00000000-0000-0000-0000-000000000001", - observed_at="2026-07-26T22:00:00Z", - valid_until="2026-07-26T22:01:00Z", - ), - ) - try: - service.start() - first = service.run_once() - first_state = service.state() - assert first["status"] == "RECONCILIATION_COMPLETE" - assert first_state.health_status == "BLOCKED" - assert first_state.reason == "INITIAL_RECONCILIATION_COMPLETE" - assert first_state.execution_enabled is False - assert first_state.rollback_anchor_current is True - result = service.run_once() - state = service.state() - - assert result["status"] == "BLOCKED" - assert state.health_status == "BLOCKED" - assert state.reason == "EXECUTION_CYCLE_BLOCKED" - assert state.execution_enabled is False - assert state.rollback_anchor_current is True - assert len(cycle_calls) == 1 - assert cycle_calls[0]["broker_snapshot"] == broker.value - assert len(anchors.calls) == 12 - - service.execution_cycle = lambda **_kwargs: { - "schema": "dummy.dumbmoney-execution-cycle.v1", - "status": "BLOCKED", - "broker_contacted": False, - "orders_submitted": 0, - "broker_snapshot_sha256": _hash("different-snapshot"), - } - with pytest.raises( - DumbMoneyWindowsServiceError, - match="execution cycle result is invalid", - ): - service.run_once() - assert service.state().execution_enabled is False - assert service.state().broker_truth_fresh is False - finally: - service.close() diff --git a/tests/test_kalshi_client.py b/tests/test_kalshi_client.py index 20420b68..01699898 100644 --- a/tests/test_kalshi_client.py +++ b/tests/test_kalshi_client.py @@ -7,65 +7,10 @@ from kalshi.signer import sign_request from kalshi.error_classifier import classify, KalshiErrorCategory - -def _json_response(payload): - return httpx.Response( - 200, - json=payload, - request=httpx.Request("GET", "https://kalshi.invalid/test"), - ) - - @pytest.fixture def client(): return KalshiClient() - -def test_production_client_rejects_ambient_endpoint_redirect(monkeypatch): - monkeypatch.setenv("KALSHI_API_BASE", "https://attacker.invalid") - monkeypatch.setenv("KALSHI_API_VERSION", "trade-api/v999") - - with pytest.raises(RuntimeError, match="KALSHI_ENDPOINT_OVERRIDE_REJECTED"): - KalshiClient() - - -def test_production_client_allows_only_exact_endpoint_pin(monkeypatch): - monkeypatch.setenv( - "KALSHI_API_BASE", - "https://external-api.kalshi.com/", - ) - monkeypatch.setenv("KALSHI_API_VERSION", "/trade-api/v2/") - - pinned = KalshiClient() - assert str(pinned.client.base_url) == ( - "https://external-api.kalshi.com/trade-api/v2/" - ) - - -def test_production_client_disables_environment_proxy_trust(monkeypatch): - monkeypatch.delenv("KALSHI_API_BASE", raising=False) - monkeypatch.delenv("KALSHI_API_VERSION", raising=False) - - with patch("kalshi.client.httpx.AsyncClient") as async_client: - KalshiClient() - - assert async_client.call_args.kwargs["trust_env"] is False - - -def test_signer_path_prefix_ignores_ambient_version_redirect(monkeypatch): - monkeypatch.setenv("KALSHI_API_KEY_ID", "test-key") - monkeypatch.setenv("KALSHI_API_VERSION", "trade-api/v999") - private_key = MagicMock() - private_key.sign.return_value = b"signature" - - with patch("kalshi.signer.load_private_key", return_value=private_key): - sign_request("GET", "/markets") - - signed_message = private_key.sign.call_args.args[0].decode("utf-8") - assert signed_message.endswith("GET/trade-api/v2/markets") - assert "v999" not in signed_message - - @pytest.mark.asyncio async def test_sign_request_requires_key_id(): os.environ.pop("KALSHI_API_KEY_ID", None) @@ -77,7 +22,9 @@ async def test_get_orderbook_parsing(client): mock_resp = {"orderbook": {"bids": [{"price": 50, "count": 10}], "asks": [{"price": 55, "count": 5}]}} with patch("kalshi.client.sign_request", return_value={"KALSHI-ACCESS-KEY": "test", "KALSHI-ACCESS-SIGNATURE": "sig", "KALSHI-ACCESS-TIMESTAMP": "ts"}) as _: with patch.object(client.client, "request", new_callable=AsyncMock) as m: - m.return_value = _json_response(mock_resp) + m.return_value.status_code = 200 + m.return_value.json = MagicMock(return_value=mock_resp) + m.return_value.raise_for_status = MagicMock() ob = await client.get_orderbook("MARKET") assert ob.bids[0].price == 50 assert ob.asks[0].size == 5 @@ -91,12 +38,14 @@ async def test_get_orderbook_parsing(client): async def test_get_orderbook_sorts_and_rejects_missing_book(client): with patch("kalshi.client.sign_request", return_value={"KALSHI-ACCESS-KEY": "test", "KALSHI-ACCESS-SIGNATURE": "sig", "KALSHI-ACCESS-TIMESTAMP": "ts"}): with patch.object(client.client, "request", new_callable=AsyncMock) as request: - request.return_value = _json_response({"orderbook": {"bids": [{"price": 48, "count": 1}, {"price": 40, "count": 1}], "asks": [{"price": 60, "count": 1}, {"price": 52, "count": 1}]}}) + request.return_value.status_code = 200 + request.return_value.raise_for_status = MagicMock() + request.return_value.json = MagicMock(return_value={"orderbook": {"bids": [{"price": 48, "count": 1}, {"price": 40, "count": 1}], "asks": [{"price": 60, "count": 1}, {"price": 52, "count": 1}]}}) book = await client.get_orderbook("MARKET") assert [level.price for level in book.bids] == [40, 48] assert [level.price for level in book.asks] == [52, 60] - request.return_value = _json_response({"orderbook": {}}) + request.return_value.json = MagicMock(return_value={"orderbook": {}}) with pytest.raises(ValueError, match="missing"): await client.get_orderbook("MARKET") @@ -139,16 +88,12 @@ async def test_create_order_signs_json_body(client): expected_body = '{"count":10,"price":50,"side":"yes","ticker":"MARKET"}' with patch("kalshi.client.sign_request") as mock_sign: with patch.object(client.client, "request", new_callable=AsyncMock) as m: - m.return_value = _json_response({"status": "success"}) - permit = await client.prepare_order_mutation( - "POST", - "/portfolio/events/orders", - _capability=_CENTRAL_FIREWALL_SUBMIT_CAPABILITY, - ) + m.return_value.status_code = 200 + m.return_value.json = MagicMock(return_value={"status": "success"}) + m.return_value.raise_for_status = MagicMock() await client.create_order( order, _capability=_CENTRAL_FIREWALL_SUBMIT_CAPABILITY, - _mutation_permit=permit, ) mock_sign.assert_called_once() signed_body = mock_sign.call_args[0][2] @@ -173,9 +118,6 @@ async def test_direct_create_order_without_central_capability_fails_before_trans ("method", "path"), [ ("POST", "/portfolio/orders"), - ("POST", "/portfolio/events/orders"), - ("DELETE", "/portfolio/events/orders/order-123"), - ("POST", "/portfolio/events/orders/order-123/amend"), ("post", "/portfolio/orders?client_order_id=ignored"), ("PATCH", "/portfolio/orders/order-123"), ( @@ -215,7 +157,7 @@ async def test_raw_order_mutation_rejects_forged_capability_before_transport(cli ): await client._request( "POST", - "/portfolio/events/orders", + "/portfolio/orders", json={"ticker": "MARKET"}, _capability=object(), ) @@ -234,18 +176,14 @@ async def test_authorized_raw_order_mutation_consumes_capability_locally(client) }, ): with patch.object(client.client, "request", new_callable=AsyncMock) as request: - request.return_value = _json_response({"order": {"order_id": "1"}}) - permit = await client.prepare_order_mutation( - "POST", - "/portfolio/events/orders", - _capability=_CENTRAL_FIREWALL_SUBMIT_CAPABILITY, - ) + request.return_value.status_code = 200 + request.return_value.json = MagicMock(return_value={"order": {"order_id": "1"}}) + request.return_value.raise_for_status = MagicMock() await client._request( "POST", - "/portfolio/events/orders", + "/portfolio/orders", json={"ticker": "MARKET"}, _capability=_CENTRAL_FIREWALL_SUBMIT_CAPABILITY, - _mutation_permit=permit, ) request.assert_awaited_once() assert "_capability" not in request.await_args.kwargs @@ -262,7 +200,9 @@ async def test_read_only_order_requests_remain_available_without_capability(clie }, ): with patch.object(client.client, "request", new_callable=AsyncMock) as request: - request.return_value = _json_response({"orders": []}) + request.return_value.status_code = 200 + request.return_value.json = MagicMock(return_value={"orders": []}) + request.return_value.raise_for_status = MagicMock() result = await client.get_orders() assert result == {"orders": []} request.assert_awaited_once() @@ -289,85 +229,3 @@ async def test_rate_limiter_retries_connect_error(client): with pytest.raises(httpx.ConnectError): await client.get_markets() assert m.call_count == client.limiter.max_retries + 1 - - -@pytest.mark.asyncio -@pytest.mark.parametrize( - "failure", - [ - httpx.ConnectError("ambiguous connection failure"), - httpx.ReadTimeout("ambiguous response timeout"), - ], -) -async def test_order_mutation_transport_is_exactly_one_attempt(client, failure): - client.limiter.base_delay = 0 - with patch( - "kalshi.client.sign_request", - return_value={ - "KALSHI-ACCESS-KEY": "test", - "KALSHI-ACCESS-SIGNATURE": "sig", - "KALSHI-ACCESS-TIMESTAMP": "ts", - }, - ): - with patch.object( - client.client, - "request", - new_callable=AsyncMock, - ) as request: - request.side_effect = failure - permit = await client.prepare_order_mutation( - "POST", - "/portfolio/events/orders", - _capability=_CENTRAL_FIREWALL_SUBMIT_CAPABILITY, - ) - with pytest.raises(type(failure)): - await client.create_order( - { - "ticker": "MARKET", - "client_order_id": "proposal-1", - }, - _capability=_CENTRAL_FIREWALL_SUBMIT_CAPABILITY, - _mutation_permit=permit, - ) - assert request.await_count == 1 - - -@pytest.mark.asyncio -async def test_order_mutation_http_429_is_not_retried(client): - response = httpx.Response( - 429, - request=httpx.Request( - "POST", - "https://kalshi.invalid/portfolio/events/orders", - ), - json={"error": "rate limited"}, - ) - with patch( - "kalshi.client.sign_request", - return_value={ - "KALSHI-ACCESS-KEY": "test", - "KALSHI-ACCESS-SIGNATURE": "sig", - "KALSHI-ACCESS-TIMESTAMP": "ts", - }, - ): - with patch.object( - client.client, - "request", - new_callable=AsyncMock, - return_value=response, - ) as request: - permit = await client.prepare_order_mutation( - "POST", - "/portfolio/events/orders", - _capability=_CENTRAL_FIREWALL_SUBMIT_CAPABILITY, - ) - with pytest.raises(httpx.HTTPStatusError): - await client.create_order( - { - "ticker": "MARKET", - "client_order_id": "proposal-1", - }, - _capability=_CENTRAL_FIREWALL_SUBMIT_CAPABILITY, - _mutation_permit=permit, - ) - assert request.await_count == 1 diff --git a/tests/test_kalshi_livebrokerfirewall_adapter.py b/tests/test_kalshi_livebrokerfirewall_adapter.py index 15c2d11e..44402ff9 100644 --- a/tests/test_kalshi_livebrokerfirewall_adapter.py +++ b/tests/test_kalshi_livebrokerfirewall_adapter.py @@ -45,6 +45,8 @@ def kalshi_env(monkeypatch, rsa_private_key_pem: str) -> dict[str, str]: env: dict[str, str] = { "KALSHI_API_KEY_ID": "test-key-id", "KALSHI_API_PRIVATE_KEY_PEM": rsa_private_key_pem, + "KALSHI_API_BASE": "http://kalshi.test", + "KALSHI_API_VERSION": "trade-api/v2", } for name, value in env.items(): monkeypatch.setenv(name, value) diff --git a/tests/test_kalshi_order_payload_schema.py b/tests/test_kalshi_order_payload_schema.py index 1919f0c7..06fb82be 100644 --- a/tests/test_kalshi_order_payload_schema.py +++ b/tests/test_kalshi_order_payload_schema.py @@ -50,7 +50,7 @@ def test_required_fields_present(): assert payload["count"] == 1 -def test_firewall_build_order_uses_event_order_v2_fixed_point_wire(): +def test_firewall_build_order_uses_side_specific_price(): from core.ontology import LiveOrderRequest from live_firewall.firewall import LiveBrokerFirewall from live_firewall.exposure_tracker import ExposureTracker @@ -66,14 +66,9 @@ def test_firewall_build_order_uses_event_order_v2_fixed_point_wire(): strategy_proof_reference="s", forecast_proof_reference="f", adapter_name="a", - expiration_ts=1_900_000_000, ) order = firewall._build_order(req) - assert order["side"] == "bid" - assert order["price"] == "0.1200" - assert order["count"] == "1.00" + assert order["yes_price"] == 12 + assert "price" not in order assert order["client_order_id"] == "prop-1" - assert order["time_in_force"] == "good_till_canceled" - assert order["post_only"] is True - assert order["expiration_time"] == 1_900_000_000 - assert order["subaccount"] == 0 + assert order["type"] == "limit" diff --git a/tests/test_kalshi_strict_json.py b/tests/test_kalshi_strict_json.py deleted file mode 100644 index 042e9c8d..00000000 --- a/tests/test_kalshi_strict_json.py +++ /dev/null @@ -1,94 +0,0 @@ -from __future__ import annotations - -import httpx -import pytest - -from kalshi.strict_json import ( - StrictJSONResponseError, - load_strict_json_response, -) - - -def _response(body: bytes) -> httpx.Response: - return httpx.Response( - 200, - content=body, - request=httpx.Request("GET", "https://kalshi.invalid/test"), - ) - - -def test_accepts_nested_strict_utf8_json() -> None: - payload = load_strict_json_response( - _response('{"market":{"ticker":"KX-✓"},"prices":[1,2]}'.encode()) - ) - - assert payload == { - "market": {"ticker": "KX-✓"}, - "prices": [1, 2], - } - - -@pytest.mark.parametrize( - "body", - [ - b'{"ticker":"A","ticker":"B"}', - b'{"market":{"ticker":"A","ticker":"B"}}', - b'[{"ticker":"A","ticker":"B"}]', - ], -) -def test_rejects_duplicate_keys_at_every_object_depth(body: bytes) -> None: - with pytest.raises(StrictJSONResponseError, match="duplicate JSON key"): - load_strict_json_response(_response(body)) - - -@pytest.mark.parametrize( - "token", - ["NaN", "Infinity", "-Infinity", "1e999999"], -) -def test_rejects_non_finite_numeric_extensions(token: str) -> None: - with pytest.raises(StrictJSONResponseError, match="non-finite"): - load_strict_json_response(_response(f'{{"price":{token}}}'.encode())) - - -def test_rejects_invalid_utf8() -> None: - with pytest.raises(StrictJSONResponseError, match="strict UTF-8 JSON"): - load_strict_json_response(_response(b'{"ticker":"\xff"}')) - - -def test_rejects_response_over_explicit_byte_limit_before_decoding() -> None: - with pytest.raises(StrictJSONResponseError, match="exceeds 7 byte limit"): - load_strict_json_response(_response(b'{"a":1} '), maximum_bytes=7) - - -@pytest.mark.asyncio -async def test_kalshi_client_rejects_duplicate_response_keys(monkeypatch) -> None: - from kalshi.client import KalshiClient - - client = KalshiClient() - - async def fake_request(*_args, **_kwargs): - return _response(b'{"markets":[],"markets":[{"ticker":"forged"}]}') - - monkeypatch.setattr(client.client, "request", fake_request) - monkeypatch.setattr( - "kalshi.client.sign_request", - lambda *_args, **_kwargs: {}, - ) - - with pytest.raises(StrictJSONResponseError, match="duplicate JSON key"): - await client.get_markets() - - -def test_public_reconciler_rejects_non_finite_response(monkeypatch) -> None: - from autonomy import reconciler - - monkeypatch.setattr( - reconciler, - "_public_get", - lambda *_args, **_kwargs: _response( - b'{"market":{"ticker":"KX","last_price":NaN}}' - ), - ) - - with pytest.raises(StrictJSONResponseError, match="non-finite"): - reconciler.default_fetch_market_result("KX") diff --git a/tests/test_live_cap_firewall_rehearsal.py b/tests/test_live_cap_firewall_rehearsal.py index 91536e90..527f77d2 100644 --- a/tests/test_live_cap_firewall_rehearsal.py +++ b/tests/test_live_cap_firewall_rehearsal.py @@ -131,10 +131,7 @@ async def test_rehearsal_blocks_by_default(): assert verdict.would_submit is False assert verdict.blocked_reason == "live_submit_disabled" assert verdict.order is not None - assert verdict.order["time_in_force"] == "good_till_canceled" - assert verdict.order["post_only"] is True - assert verdict.order["price"] == "0.5000" - assert verdict.order["count"] == "1.00" + assert verdict.order["type"] == "limit" @pytest.mark.asyncio diff --git a/tests/test_live_firewall.py b/tests/test_live_firewall.py index 1657117b..f53ea93c 100644 --- a/tests/test_live_firewall.py +++ b/tests/test_live_firewall.py @@ -463,7 +463,7 @@ async def test_submit_creates_order_and_tracks_exposure(): assert len(exposure.order_history) == 1 assert exposure.open_order_count() == 1 assert exposure.positions == {} - assert exposure.total_exposure_cents() == 52 + assert exposure.total_exposure_cents() == 50 client.create_order.assert_awaited_once() diff --git a/tests/test_live_firewall_exposure_truth.py b/tests/test_live_firewall_exposure_truth.py index e74e52c9..3e335f1e 100644 --- a/tests/test_live_firewall_exposure_truth.py +++ b/tests/test_live_firewall_exposure_truth.py @@ -18,10 +18,6 @@ def _pass_non_metadata_gates(monkeypatch, firewall: LiveBrokerFirewall) -> None: - monkeypatch.setattr( - "live_firewall.firewall.load_caps", - lambda: CapConfig(allowed_markets=["MARKET"]), - ) monkeypatch.setattr( firewall, "evaluate", @@ -32,16 +28,6 @@ def _pass_non_metadata_gates(monkeypatch, firewall: LiveBrokerFirewall) -> None: "_autonomy_risk_verdict", lambda request, required=False: ALLOW, ) - monkeypatch.setattr( - firewall, - "_net_ev_verdict", - lambda request, forecast, caps: ALLOW, - ) - monkeypatch.setattr( - firewall, - "_model_influence_verdict", - lambda request, forecast: ALLOW, - ) monkeypatch.setattr( firewall, "_canary_readiness_verdict", @@ -83,7 +69,7 @@ async def test_accepted_order_is_reserved_but_not_a_position(monkeypatch) -> Non assert exposure.open_order_count() == 1 assert exposure.open_orders[0]["state"] == "open" assert exposure.open_orders[0]["remaining_size"] == 1 - assert exposure.total_exposure_cents() == 52 + assert exposure.total_exposure_cents() == 50 assert len(exposure.order_history) == 1 client.create_order.assert_awaited_once() @@ -105,11 +91,11 @@ async def test_unknown_transport_keeps_full_conservative_reservation(monkeypatch assert result.success is False assert result.broker_contacted is True - assert result.error == "AMBIGUOUS_BROKER_OUTCOME:TimeoutError" + assert result.error == "broker_submit_failed:TimeoutError" assert exposure.positions == {} assert exposure.open_order_count() == 1 assert exposure.open_orders[0]["state"] == "submit_outcome_unknown" - assert exposure.total_exposure_cents() == 52 + assert exposure.total_exposure_cents() == 50 def test_partial_fills_are_cumulative_and_reserve_the_remainder() -> None: @@ -123,26 +109,26 @@ def test_partial_fills_are_cumulative_and_reserve_the_remainder() -> None: side="yes", ) assert exposure.positions == {} - assert exposure.total_exposure_cents() == 247 + assert exposure.total_exposure_cents() == 240 assert exposure.record_cumulative_fill("broker-1", 1, 50) is True position = exposure.positions[("MARKET", "yes")] assert position.quantity == 1 assert position.avg_price_cents == 50 assert exposure.open_orders[0]["remaining_size"] == 3 - assert exposure.total_exposure_cents() == 50 + 3 * 60 + 7 + assert exposure.total_exposure_cents() == 50 + 3 * 60 assert exposure.record_cumulative_fill("broker-1", 3, 54) is True position = exposure.positions[("MARKET", "yes")] assert position.quantity == 3 assert position.avg_price_cents == 54 assert exposure.open_orders[0]["remaining_size"] == 1 - assert exposure.total_exposure_cents() == 3 * 54 + 60 + 7 + assert exposure.total_exposure_cents() == 3 * 54 + 60 # Replaying the same cumulative witness cannot double count the fill. assert exposure.record_cumulative_fill("broker-1", 3, 54) is True assert exposure.positions[("MARKET", "yes")].quantity == 3 - assert exposure.total_exposure_cents() == 3 * 54 + 60 + 7 + assert exposure.total_exposure_cents() == 3 * 54 + 60 # A witnessed cancel releases only the unfilled remainder. assert exposure.record_cumulative_fill( @@ -155,102 +141,14 @@ def test_partial_fills_are_cumulative_and_reserve_the_remainder() -> None: def test_stale_reservation_survives_persistence_reload(tmp_path) -> None: state_path = tmp_path / "exposure.json" first = ExposureTracker(persist=True, state_path=state_path) - empty_head = first.anchor_head() - assert empty_head[0] == 0 - assert first.reserve_order_submission( - "client-1", - "MARKET", - 2, - 49, - contract_ticker="MARKET", - side="yes", - ) is True - reserved_head = first.anchor_head() - assert reserved_head[0] == 1 - assert reserved_head[1] != empty_head[1] + assert first.reserve_order_submission("client-1", "MARKET", 2, 49) is True reloaded = ExposureTracker(persist=True, state_path=state_path) assert reloaded.state_healthy is True - assert reloaded.anchor_head() == reserved_head assert reloaded.open_order_count() == 1 assert reloaded.open_orders[0]["state"] == "submitting" - assert reloaded.total_exposure_cents() == 102 - - -def test_exposure_anchor_exposes_byte_rollback_as_revision_regression( - tmp_path, -) -> None: - state_path = tmp_path / "exposure.json" - tracker = ExposureTracker(persist=True, state_path=state_path) - assert tracker.reserve_order_submission( - "client-1", - "MARKET", - 1, - 49, - contract_ticker="MARKET", - side="yes", - ) - earlier_bytes = state_path.read_bytes() - earlier_head = tracker.anchor_head() - assert tracker.confirm_open_order("client-1", "broker-1") - later_head = tracker.anchor_head() - assert later_head[0] > earlier_head[0] - assert later_head[1] != earlier_head[1] - - state_path.write_bytes(earlier_bytes) - rolled_back = ExposureTracker(persist=True, state_path=state_path) - assert rolled_back.state_healthy is True - assert rolled_back.anchor_head() == earlier_head - - -def test_terminal_reconciliation_is_idempotent_after_restart(tmp_path) -> None: - state_path = tmp_path / "exposure.json" - first = ExposureTracker(persist=True, state_path=state_path) - assert first.reserve_order_submission( - "proposal-1", - "MARKET", - 1, - 50, - contract_ticker="MARKET", - side="yes", - ) is True - assert first.confirm_open_order("proposal-1", "broker-1") is True - reconciliation_id = "a" * 64 - assert first.record_cumulative_fill( - "proposal-1", - 1, - 50, - terminal_state="filled", - reconciliation_id=reconciliation_id, - ) is True - - reloaded = ExposureTracker(persist=True, state_path=state_path) - assert reloaded.record_cumulative_fill( - "proposal-1", - 1, - 50, - terminal_state="filled", - reconciliation_id=reconciliation_id, - ) is True - assert reloaded.state_healthy is True - assert reloaded.open_order_count() == 0 - assert reloaded.positions[("MARKET", "yes")].quantity == 1 - - settlement_id = "b" * 64 - assert reloaded.record_position_close( - "MARKET", - "yes", - reconciliation_id=settlement_id, - ) is True - settled = ExposureTracker(persist=True, state_path=state_path) - assert settled.record_position_close( - "MARKET", - "yes", - reconciliation_id=settlement_id, - ) is True - assert settled.state_healthy is True - assert settled.positions == {} + assert reloaded.total_exposure_cents() == 98 @pytest.mark.asyncio diff --git a/tests/test_live_kalshi.py b/tests/test_live_kalshi.py index 2037cafb..f75b62de 100644 --- a/tests/test_live_kalshi.py +++ b/tests/test_live_kalshi.py @@ -2,9 +2,8 @@ import os from datetime import datetime, timezone from pathlib import Path -from unittest.mock import AsyncMock, patch +from unittest.mock import AsyncMock, MagicMock, patch -import httpx import pytest from core import secret_guard @@ -29,11 +28,9 @@ def mock_sign(): def _mock_response(data): m = AsyncMock() - m.return_value = httpx.Response( - 200, - json=data, - request=httpx.Request("GET", "https://kalshi.invalid/test"), - ) + m.return_value.status_code = 200 + m.return_value.json = MagicMock(return_value=data) + m.return_value.raise_for_status = MagicMock() return m diff --git a/tests/test_reconciler_transport_safety.py b/tests/test_reconciler_transport_safety.py deleted file mode 100644 index 7f73e609..00000000 --- a/tests/test_reconciler_transport_safety.py +++ /dev/null @@ -1,35 +0,0 @@ -from unittest.mock import MagicMock, patch - -import autonomy.reconciler as reconciler -import httpx - - -def test_public_base_ignores_ambient_endpoint_redirect(monkeypatch): - monkeypatch.setenv("KALSHI_API_BASE", "https://attacker.invalid") - monkeypatch.setenv("KALSHI_API_VERSION", "trade-api/v999") - - assert ( - reconciler._public_base() - == "https://external-api.kalshi.com/trade-api/v2" - ) - - -def test_public_fetch_disables_environment_proxy_trust(): - response = httpx.Response( - 200, - json={"market": {"ticker": "TEST"}}, - request=httpx.Request("GET", "https://kalshi.invalid/markets/TEST"), - ) - client = MagicMock() - client.__enter__.return_value = client - client.get.return_value = response - - with patch("httpx.Client", return_value=client) as client_type: - result = reconciler.default_fetch_market_result("TEST") - - assert result == {"ticker": "TEST"} - assert client_type.call_args.kwargs["trust_env"] is False - assert client_type.call_args.kwargs["base_url"] == ( - "https://external-api.kalshi.com/trade-api/v2" - ) - client.get.assert_called_once_with("/markets/TEST", params=None) diff --git a/tests/test_risk_state_persistence.py b/tests/test_risk_state_persistence.py index 63630da4..a9071cb2 100644 --- a/tests/test_risk_state_persistence.py +++ b/tests/test_risk_state_persistence.py @@ -2,12 +2,6 @@ from __future__ import annotations -import json -import threading -from concurrent.futures import ThreadPoolExecutor - -import pytest - from core.kalshi_market_validator import validate_ticker_shape from core.ontology import CapConfig, Position from core.state import DummyState @@ -40,71 +34,6 @@ def test_daily_realized_loss_persists_and_is_idempotent(tmp_path): assert DummyState(persist=True, state_path=path).daily_loss_cents == 150 -def test_concurrent_stale_states_merge_daily_losses(tmp_path): - path = tmp_path / "risk_state.json" - first = DummyState(persist=True, state_path=path) - second = DummyState(persist=True, state_path=path) - barrier = threading.Barrier(2) - - def record(state: DummyState, loss: int, settlement_id: str) -> bool: - barrier.wait(timeout=5) - return state.record_realized_pnl( - -loss, - settlement_id=settlement_id, - ) - - with ThreadPoolExecutor(max_workers=2) as executor: - results = [ - future.result() - for future in ( - executor.submit(record, first, 100, "settlement-a"), - executor.submit(record, second, 200, "settlement-b"), - ) - ] - - assert results == [True, True] - reloaded = DummyState(persist=True, state_path=path) - assert reloaded.daily_loss_cents == 300 - payload = json.loads(path.read_text(encoding="utf-8")) - assert payload["processed_settlement_ids"] == [ - "settlement-a", - "settlement-b", - ] - - -def test_stale_risk_verifier_cannot_erase_kill_or_newer_loss(tmp_path): - path = tmp_path / "risk_state.json" - stale = DummyState(persist=True, state_path=path) - writer = DummyState(persist=True, state_path=path) - - assert writer.record_realized_pnl( - -125, - settlement_id="settlement-a", - ) - assert writer.enable_kill_switch("operator stop") - assert stale.verify_persistence() is True - - reloaded = DummyState(persist=True, state_path=path) - assert reloaded.kill_switch.active is True - assert reloaded.kill_switch.reason == "operator stop" - assert reloaded.daily_loss_cents == 125 - - -def test_stale_kill_clear_cannot_clear_newer_reassertion(tmp_path): - path = tmp_path / "risk_state.json" - initial = DummyState(persist=True, state_path=path) - assert initial.enable_kill_switch("first stop") - stale = DummyState(persist=True, state_path=path) - writer = DummyState(persist=True, state_path=path) - assert writer.enable_kill_switch("newer stop") - - assert stale.disable_kill_switch() is False - - reloaded = DummyState(persist=True, state_path=path) - assert reloaded.kill_switch.active is True - assert reloaded.kill_switch.reason == "newer stop" - - def test_corrupt_daily_loss_state_is_not_treated_as_zero(tmp_path): path = tmp_path / "risk_state.json" path.write_text("{", encoding="utf-8") @@ -131,8 +60,8 @@ def test_exposure_persists_both_sides_without_overwrite(tmp_path): ("KXBTC-EVENT", "no"), } # Filled positions reserve 40c + 60c and the still-open YES order reserves - # another 40c plus the conservative 2c fee reserve. - assert reloaded.total_exposure_cents() == 142 + # another 40c. Counting both prevents capital from being double-spent. + assert reloaded.total_exposure_cents() == 140 assert reloaded.open_order_count() == 1 reloaded.remove_open_order("order-1") @@ -142,100 +71,6 @@ def test_exposure_persists_both_sides_without_overwrite(tmp_path): assert set(final.positions) == {("KXBTC-EVENT", "no")} -def test_stale_exposure_verifier_cannot_erase_reservation(tmp_path): - path = tmp_path / "exposure.json" - writer = ExposureTracker(persist=True, state_path=path) - stale = ExposureTracker(persist=True, state_path=path) - - assert writer.reserve_order_submission( - "order-a", - "KXBTC-EVENT", - 1, - 40, - contract_ticker="KXBTC-EVENT", - side="yes", - ) - assert stale.verify_persistence() is True - - reloaded = ExposureTracker(persist=True, state_path=path) - assert [ - order["client_order_id"] for order in reloaded.open_orders - ] == ["order-a"] - - -def test_concurrent_exposure_reservations_merge_and_dedupe(tmp_path): - path = tmp_path / "exposure.json" - first = ExposureTracker(persist=True, state_path=path) - second = ExposureTracker(persist=True, state_path=path) - barrier = threading.Barrier(2) - - def reserve( - tracker: ExposureTracker, - client_order_id: str, - ) -> bool: - barrier.wait(timeout=5) - return tracker.reserve_order_submission( - client_order_id, - "KXBTC-EVENT", - 1, - 40, - contract_ticker="KXBTC-EVENT", - side="yes", - ) - - with ThreadPoolExecutor(max_workers=2) as executor: - distinct_results = [ - future.result() - for future in ( - executor.submit(reserve, first, "order-a"), - executor.submit(reserve, second, "order-b"), - ) - ] - assert distinct_results == [True, True] - reloaded = ExposureTracker(persist=True, state_path=path) - assert { - order["client_order_id"] for order in reloaded.open_orders - } == {"order-a", "order-b"} - assert reloaded.total_exposure_cents() == 84 - - duplicate_first = ExposureTracker( - persist=True, - state_path=tmp_path / "dedupe.json", - ) - duplicate_second = ExposureTracker( - persist=True, - state_path=tmp_path / "dedupe.json", - ) - duplicate_barrier = threading.Barrier(2) - - def reserve_duplicate(tracker: ExposureTracker) -> bool: - duplicate_barrier.wait(timeout=5) - return tracker.reserve_order_submission( - "same-order", - "KXBTC-EVENT", - 1, - 40, - contract_ticker="KXBTC-EVENT", - side="yes", - ) - - with ThreadPoolExecutor(max_workers=2) as executor: - duplicate_results = [ - future.result() - for future in ( - executor.submit(reserve_duplicate, duplicate_first), - executor.submit(reserve_duplicate, duplicate_second), - ) - ] - assert sorted(duplicate_results) == [False, True] - deduped = ExposureTracker( - persist=True, - state_path=tmp_path / "dedupe.json", - ) - assert len(deduped.open_orders) == 1 - assert deduped.open_orders[0]["client_order_id"] == "same-order" - - def test_corrupt_exposure_state_fails_closed(tmp_path): path = tmp_path / "exposure.json" path.write_text("not-json", encoding="utf-8") @@ -245,52 +80,6 @@ def test_corrupt_exposure_state_fails_closed(tmp_path): assert tracker.state_healthy is False -def test_negative_persisted_position_cannot_offset_live_reservations(tmp_path): - path = tmp_path / "negative-exposure.json" - path.write_text( - json.dumps( - { - "positions": [ - { - "market_ticker": "KXBTC-EVENT", - "contract_ticker": "KXBTC-EVENT", - "side": "yes", - "quantity": -10, - "avg_price_cents": 50, - "unrealized_pnl_cents": 0, - "source_ts": None, - "freshness_score": None, - } - ], - "open_orders": [], - "order_history": [], - "updated_at": "2026-07-26T22:00:00+00:00", - } - ), - encoding="utf-8", - ) - - tracker = ExposureTracker(persist=True, state_path=path) - - assert tracker.state_healthy is False - assert tracker.total_exposure_cents() == 2**63 - 1 - - -def test_position_mutation_rejects_negative_risk() -> None: - tracker = ExposureTracker() - negative = Position( - market_ticker="KXBTC-EVENT", - contract_ticker="KXBTC-EVENT", - side="yes", - quantity=-1, - avg_price_cents=50, - unrealized_pnl_cents=0, - ) - - with pytest.raises(ValueError, match="invalid exposure position"): - tracker.update_position(negative) - - def test_blocked_category_matching_is_case_insensitive(): caps = CapConfig(blocked_categories=["kxpolitics"]) diff --git a/tests/test_sqlite_operational_journal.py b/tests/test_sqlite_operational_journal.py deleted file mode 100644 index 14929ba4..00000000 --- a/tests/test_sqlite_operational_journal.py +++ /dev/null @@ -1,528 +0,0 @@ -from __future__ import annotations - -import json -import multiprocessing -import sqlite3 -from datetime import datetime, timezone -from pathlib import Path -from typing import Any - -import pytest - -from live_firewall.operational_journal import ( - AppendOnlyOperationalJournal, - OPERATIONAL_EVENT_SCHEMA, - OperationalJournalError, - canonical_json, - sha256_json, -) -from live_firewall.sqlite_operational_journal import ( - SQLITE_OPERATIONAL_JOURNAL_SCHEMA, - SQLiteOperationalJournal, -) - - -NOW = datetime(2026, 7, 26, 12, 30, tzinfo=timezone.utc) - - -def _claim_in_process( - database_path: str, - worker_id: int, - start: Any, - results: Any, -) -> None: - journal = SQLiteOperationalJournal( - Path(database_path), - now_fn=lambda: NOW, - busy_timeout_seconds=10, - ) - try: - if not journal.healthy: - results.put(("unhealthy", journal.error)) - return - if not start.wait(timeout=15): - results.put(("timeout", worker_id)) - return - - def no_prior_claim(rows: tuple[dict[str, Any], ...]) -> None: - if any(row.get("kind") == "dispatch.claimed" for row in rows): - raise OperationalJournalError("dispatch is already claimed") - - event = journal.append( - "dispatch.claimed", - {"worker_id": worker_id}, - outbox_id=f"dispatch-claim:{worker_id}", - allow_existing_outbox=False, - validate_existing=no_prior_claim, - validate_existing_latest_kinds=("dispatch.claimed",), - ) - results.put(("committed", event["sequence"])) - except OperationalJournalError as exc: - results.put(("rejected", str(exc))) - finally: - journal.close() - - -def test_restart_preserves_chain_idempotency_and_outbox_state( - tmp_path: Path, -) -> None: - path = tmp_path / "operational.db" - journal = SQLiteOperationalJournal(path, now_fn=lambda: NOW) - assert journal.healthy, journal.error - - source = journal.append( - "capital.reserved", - {"reservation_id": "reservation-1", "cents": 125}, - outbox_id="reservation:1", - ) - assert ( - journal.append( - "capital.reserved", - {"reservation_id": "reservation-1", "cents": 125}, - outbox_id="reservation:1", - ) - == source - ) - with pytest.raises( - OperationalJournalError, - match="reused with different content", - ): - journal.append( - "capital.reserved", - {"reservation_id": "reservation-1", "cents": 126}, - outbox_id="reservation:1", - ) - - other = journal.append( - "capital.reserved", - {"reservation_id": "reservation-2", "cents": 75}, - outbox_id="reservation:2", - ) - acknowledgement = journal.acknowledge_outbox( - "reservation:1", - acknowledgement={"receipt_id": "receipt-1"}, - ) - assert journal.pending_outbox() == (other,) - journal.close() - - restarted = SQLiteOperationalJournal(path, now_fn=lambda: NOW) - assert restarted.healthy, restarted.error - rows = restarted.events() - assert [row["sequence"] for row in rows] == [1, 2, 3] - assert rows[0] == source - assert rows[2] == acknowledgement - assert rows[2]["previous_sha256"] == rows[1]["event_sha256"] - assert rows[0]["schema"] == OPERATIONAL_EVENT_SCHEMA - assert restarted.pending_outbox() == (other,) - - with pytest.raises(OperationalJournalError, match="already claimed"): - restarted.append( - "capital.reserved", - {"reservation_id": "reservation-1", "cents": 125}, - outbox_id="reservation:1", - allow_existing_outbox=False, - ) - assert restarted.healthy - restarted.close() - - -def test_event_contract_matches_jsonl_reference(tmp_path: Path) -> None: - sqlite_journal = SQLiteOperationalJournal( - tmp_path / "contract.db", - now_fn=lambda: NOW, - ) - jsonl_journal = AppendOnlyOperationalJournal( - tmp_path / "contract.jsonl", - now_fn=lambda: NOW, - ) - assert sqlite_journal.head() == (0, "0" * 64) - assert jsonl_journal.head() == (0, "0" * 64) - - sqlite_source = sqlite_journal.append( - "broker.bootstrap.recorded", - {"receipt_id": "bootstrap-1", "orders": []}, - outbox_id="bootstrap:1", - ) - jsonl_source = jsonl_journal.append( - "broker.bootstrap.recorded", - {"receipt_id": "bootstrap-1", "orders": []}, - outbox_id="bootstrap:1", - ) - assert sqlite_source == jsonl_source - assert sqlite_journal.head() == ( - sqlite_source["sequence"], - sqlite_source["event_sha256"], - ) - assert jsonl_journal.head() == sqlite_journal.head() - - sqlite_ack = sqlite_journal.acknowledge_outbox( - "bootstrap:1", - acknowledgement={"delivered": True}, - ) - jsonl_ack = jsonl_journal.acknowledge_outbox( - "bootstrap:1", - acknowledgement={"delivered": True}, - ) - assert sqlite_ack == jsonl_ack - assert sqlite_journal.events() == jsonl_journal.events() - assert sqlite_journal.pending_outbox() == jsonl_journal.pending_outbox() - assert sqlite_journal.head() == ( - sqlite_ack["sequence"], - sqlite_ack["event_sha256"], - ) - assert jsonl_journal.head() == sqlite_journal.head() - sqlite_journal.close() - - -def test_jsonl_reference_supports_bounded_latest_kind_validation( - tmp_path: Path, -) -> None: - journal = AppendOnlyOperationalJournal( - tmp_path / "reference.jsonl", - now_fn=lambda: NOW, - ) - journal.append("state", {"cursor": 1}) - latest = journal.append("state", {"cursor": 2}) - journal.append("unrelated", {"value": 3}) - observed: list[tuple[dict[str, Any], ...]] = [] - - journal.append( - "state", - {"cursor": 3}, - validate_existing=observed.append, - validate_existing_latest_kinds=("state",), - ) - assert observed == [(latest,)] - - -def test_two_live_instances_incrementally_observe_committed_tail( - tmp_path: Path, -) -> None: - path = tmp_path / "two-live-instances.db" - first = SQLiteOperationalJournal(path, now_fn=lambda: NOW) - second = SQLiteOperationalJournal(path, now_fn=lambda: NOW) - assert first.healthy and second.healthy - - first_event = first.append( - "command.applied", - {"command_id": "command-1"}, - outbox_id="command:1", - ) - assert second.events(after_sequence=0, limit=1) == (first_event,) - - second_event = second.append( - "command.applied", - {"command_id": "command-2"}, - outbox_id="command:2", - ) - assert first.events(after_sequence=first_event["sequence"]) == ( - second_event, - ) - assert first.healthy and second.healthy - first.close() - second.close() - - -def test_serialized_operation_rolls_back_all_appends_and_cached_head( - tmp_path: Path, -) -> None: - path = tmp_path / "transaction-rollback.db" - journal = SQLiteOperationalJournal(path, now_fn=lambda: NOW) - - with pytest.raises(RuntimeError, match="handler failed"): - with journal.serialized_operation(): - journal.append("command.received", {"command_id": "one"}) - journal.append("command.applied", {"command_id": "one"}) - raise RuntimeError("handler failed after second append") - - assert journal.healthy, journal.error - assert journal.events() == () - replacement = journal.append( - "command.failed", - {"command_id": "one"}, - ) - assert replacement["sequence"] == 1 - assert replacement["previous_sha256"] == "0" * 64 - journal.close() - - -def test_latest_kind_validation_view_is_bounded_and_atomic( - tmp_path: Path, -) -> None: - path = tmp_path / "latest-kind-cas.db" - journal = SQLiteOperationalJournal(path, now_fn=lambda: NOW) - with journal.serialized_operation(): - for index in range(100): - journal.append("irrelevant.telemetry", {"index": index}) - prior = journal.append( - "command-feed.state.persisted", - {"cursor": 10}, - ) - for index in range(100, 200): - journal.append("irrelevant.telemetry", {"index": index}) - - observed: list[tuple[dict[str, Any], ...]] = [] - - def validate_latest(rows: tuple[dict[str, Any], ...]) -> None: - observed.append(rows) - assert rows == (prior,) - - appended = journal.append( - "command-feed.state.persisted", - {"cursor": 11}, - validate_existing=validate_latest, - validate_existing_latest_kinds=("command-feed.state.persisted",), - ) - assert appended["sequence"] == 202 - assert observed == [(prior,)] - journal.close() - - -def test_begin_immediate_makes_cross_process_validation_one_shot( - tmp_path: Path, -) -> None: - path = tmp_path / "claims.db" - initial = SQLiteOperationalJournal(path, now_fn=lambda: NOW) - assert initial.healthy, initial.error - initial.close() - - context = multiprocessing.get_context("spawn") - start = context.Event() - results = context.Queue() - processes = [ - context.Process( - target=_claim_in_process, - args=(str(path), worker_id, start, results), - ) - for worker_id in range(4) - ] - for process in processes: - process.start() - start.set() - observed = [results.get(timeout=30) for _ in processes] - for process in processes: - process.join(timeout=30) - assert process.exitcode == 0 - - assert sum(result[0] == "committed" for result in observed) == 1 - assert sum(result[0] == "rejected" for result in observed) == 3 - - restarted = SQLiteOperationalJournal(path, now_fn=lambda: NOW) - claims = restarted.events(kind="dispatch.claimed") - assert len(claims) == 1 - assert claims[0]["sequence"] == 1 - restarted.close() - - -def test_live_instance_detects_mid_chain_tamper_plus_valid_tail_append( - tmp_path: Path, -) -> None: - path = tmp_path / "live-tamper.db" - journal = SQLiteOperationalJournal(path, now_fn=lambda: NOW) - journal.append("authority.granted", {"scope": "first"}) - journal.append("authority.granted", {"scope": "second"}) - - with sqlite3.connect(path) as connection: - trigger_sql = connection.execute( - "SELECT sql FROM sqlite_master " - "WHERE type = 'trigger' " - "AND name = 'operational_events_no_update'" - ).fetchone()[0] - event_json = connection.execute( - "SELECT event_json FROM operational_events WHERE sequence = 1" - ).fetchone()[0] - event = json.loads(event_json) - event["payload"]["scope"] = "tampered" - connection.execute("DROP TRIGGER operational_events_no_update") - connection.execute( - "UPDATE operational_events SET event_json = ? WHERE sequence = 1", - (canonical_json(event),), - ) - connection.execute(trigger_sql) - event_count, head = connection.execute( - "SELECT event_count, head_sha256 FROM journal_metadata " - "WHERE singleton = 1" - ).fetchone() - tail = { - "schema": OPERATIONAL_EVENT_SCHEMA, - "sequence": event_count + 1, - "recorded_at": "2026-07-26T12:31:00Z", - "kind": "authority.granted", - "payload": {"scope": "valid-tail"}, - "previous_sha256": head, - } - tail["event_sha256"] = sha256_json(tail) - connection.execute( - "INSERT INTO operational_events (" - "sequence, kind, outbox_id, acknowledges_outbox_id, " - "previous_sha256, event_sha256, event_json" - ") VALUES (?, ?, NULL, NULL, ?, ?, ?)", - ( - tail["sequence"], - tail["kind"], - tail["previous_sha256"], - tail["event_sha256"], - canonical_json(tail), - ), - ) - - assert not journal.healthy - assert journal.error is not None - assert "hash" in journal.error.casefold() - journal.close() - - -@pytest.mark.parametrize( - ("mutation_sql", "expected_error"), - [ - ( - "CREATE INDEX unauthorized_payload_idx " - "ON operational_events(event_json)", - "schema object set mismatch", - ), - ("PRAGMA user_version = 99", "schema version mismatch"), - ], -) -def test_live_instance_rejects_schema_or_version_mutation( - tmp_path: Path, - mutation_sql: str, - expected_error: str, -) -> None: - path = tmp_path / "schema-mutation.db" - journal = SQLiteOperationalJournal(path, now_fn=lambda: NOW) - journal.append("authority.granted", {"scope": "one"}) - - with sqlite3.connect(path) as connection: - connection.execute(mutation_sql) - - assert not journal.healthy - assert journal.error is not None - assert expected_error in journal.error - journal.close() - - -@pytest.mark.parametrize("tamper", ["event", "head"]) -def test_restart_fails_closed_on_event_or_head_tamper( - tmp_path: Path, - tamper: str, -) -> None: - path = tmp_path / f"tamper-{tamper}.db" - journal = SQLiteOperationalJournal(path, now_fn=lambda: NOW) - journal.append("authority.granted", {"scope": "single-order"}) - journal.close() - - with sqlite3.connect(path) as connection: - if tamper == "head": - connection.execute( - "UPDATE journal_metadata SET head_sha256 = ? " - "WHERE singleton = 1", - ("f" * 64,), - ) - else: - trigger_sql = connection.execute( - "SELECT sql FROM sqlite_master " - "WHERE type = 'trigger' " - "AND name = 'operational_events_no_update'" - ).fetchone()[0] - event_json = connection.execute( - "SELECT event_json FROM operational_events WHERE sequence = 1" - ).fetchone()[0] - event = json.loads(event_json) - event["payload"]["scope"] = "tampered-unbounded" - connection.execute("DROP TRIGGER operational_events_no_update") - connection.execute( - "UPDATE operational_events SET event_json = ? " - "WHERE sequence = 1", - (canonical_json(event),), - ) - connection.execute(trigger_sql) - - restarted = SQLiteOperationalJournal(path, now_fn=lambda: NOW) - assert not restarted.healthy - assert restarted.error is not None - assert any( - marker in restarted.error.casefold() - for marker in ("hash", "head") - ) - with pytest.raises(OperationalJournalError, match="unhealthy"): - restarted.events() - restarted.close() - - -def test_bounded_incremental_reads_use_kind_and_outbox_indexes( - tmp_path: Path, -) -> None: - path = tmp_path / "bounded.db" - journal = SQLiteOperationalJournal( - path, - now_fn=lambda: NOW, - scan_batch_size=7, - ) - with journal.serialized_operation(): - for index in range(2_000): - journal.append( - "kind.even" if index % 2 == 0 else "kind.odd", - {"index": index}, - outbox_id=f"event:{index}", - ) - - page = journal.events( - kind="kind.even", - after_sequence=40, - limit=6, - ) - assert len(page) == 6 - assert [row["sequence"] for row in page] == [41, 43, 45, 47, 49, 51] - - pending_page = journal.pending_outbox( - after_sequence=1_980, - limit=4, - ) - assert [row["sequence"] for row in pending_page] == [ - 1_981, - 1_982, - 1_983, - 1_984, - ] - journal.close() - - with sqlite3.connect(path) as connection: - metadata = connection.execute( - "SELECT schema, event_count FROM journal_metadata " - "WHERE singleton = 1" - ).fetchone() - assert metadata == (SQLITE_OPERATIONAL_JOURNAL_SCHEMA, 2_000) - - indexes = { - row[0] - for row in connection.execute( - "SELECT name FROM sqlite_master WHERE type = 'index'" - ) - } - assert "operational_events_kind_sequence_idx" in indexes - assert "operational_events_outbox_sequence_idx" in indexes - assert "operational_events_ack_target_idx" in indexes - - kind_plan = " ".join( - str(row[3]) - for row in connection.execute( - "EXPLAIN QUERY PLAN " - "SELECT event_json FROM operational_events " - "WHERE kind = ? AND sequence > ? " - "ORDER BY sequence LIMIT ?", - ("kind.even", 40, 6), - ) - ) - assert "operational_events_kind_sequence_idx" in kind_plan - - outbox_plan = " ".join( - str(row[3]) - for row in connection.execute( - "EXPLAIN QUERY PLAN " - "SELECT event_json FROM operational_events " - "WHERE outbox_id = ?", - ("event:1999",), - ) - ) - assert "INDEX" in outbox_plan - assert "SCAN operational_events" not in outbox_plan diff --git a/tests/test_taker_execution_truth.py b/tests/test_taker_execution_truth.py index d2910888..cc79d5ac 100644 --- a/tests/test_taker_execution_truth.py +++ b/tests/test_taker_execution_truth.py @@ -235,53 +235,6 @@ def test_live_reconciliation_records_weighted_price_role_cost_and_fee(tmp_path): ledger.close() -@pytest.mark.parametrize( - "broker_fill_count", - ["0.50", "-1.00", "NaN", "not-a-number"], -) -def test_nonintegral_or_invalid_terminal_fill_is_retained_without_truncation( - tmp_path, - broker_fill_count, -): - ledger = AutonomyLedger(tmp_path / "ledger.db") - try: - decision = _decision() - ledger.record_decision(decision) - ledger.record_outcome(TradeOutcome( - decision_id=decision.decision_id, - market_ticker=TICKER, - kind=OutcomeKind.ACCEPTED, - order_id="order-fractional", - fill_count=0, - fill_price_cents=50, - pnl_cents=None, - broker_contacted=True, - detail={ - "submitted_price_cents": 50, - "submitted_count": 2, - "submitted_notional_cents": 100, - "liquidity_role": "maker", - }, - )) - reconciler = Reconciler( - ledger, - order_status_fn=lambda _order_id: {"order": { - "status": "canceled", - "fill_count_fp": broker_fill_count, - "maker_fill_cost_dollars": "0.2500", - }}, - ) - - updates = reconciler.reconcile_open_orders() - - assert updates == [] - pending = ledger.open_decisions("live")[0] - assert pending["order_active"] == 1 - assert pending["filled_count"] == 0 - finally: - ledger.close() - - @pytest.mark.parametrize("liquidity_role", ["maker", "taker"]) def test_settlement_uses_witnessed_price_and_correct_role_fee(liquidity_role): class _Ledger: