diff --git a/backend/main.py b/backend/main.py index aedf2a6..de567ff 100644 --- a/backend/main.py +++ b/backend/main.py @@ -1,4 +1,4 @@ -import os +import os from dotenv import load_dotenv load_dotenv() @@ -139,8 +139,8 @@ def _check_explicit_scoped_auth_local( if not admin_key and not scoped_tokens: if _allow_insecure_admin() or (_debug_mode_enabled() and host == "test"): return True, "ok", "debug_override" - return False, "Forbidden ΓÇö admin key not configured", "" - return False, "Forbidden ΓÇö invalid or missing admin key", "" + return False, "Forbidden — admin key not configured", "" + return False, "Forbidden — invalid or missing admin key", "" def _gate_privileged_access_status_snapshot_local() -> dict[str, Any]: @@ -164,7 +164,7 @@ def _gate_privileged_access_status_snapshot_local() -> dict[str, Any]: # Docker Swarm Secrets support # For each VAR below, if VAR_FILE is set (e.g. AIS_API_KEY_FILE=/run/secrets/AIS_API_KEY), # the file is read and its trimmed content is placed into VAR. -# This MUST run before service imports ├óΓé¼ΓÇ¥ modules read os.environ at import time. +# This MUST run before service imports — modules read os.environ at import time. # --------------------------------------------------------------------------- _SECRET_VARS = [ "AIS_API_KEY", @@ -213,7 +213,7 @@ if not _MESH_ONLY: from services.ais_stream import start_ais_stream, stop_ais_stream from services.carrier_tracker import start_carrier_tracker, stop_carrier_tracker else: - # Lean mesh/wormhole process ΓÇö avoid importing the OSINT fetcher graph. + # Lean mesh/wormhole process — avoid importing the OSINT fetcher graph. def start_scheduler(*_a, **_k): # type: ignore[misc] return None @@ -1643,7 +1643,7 @@ def _peer_sync_response(peer_url: str, body: dict[str, Any]) -> dict[str, Any]: # HTTP 429 must be surfaced as a typed exception carrying the # Retry-After value, so finish_sync can honor it and stop hammering # the upstream. Pre-fix this path just stringified the status into - # a ValueError, which finish_sync then ignored ΓÇö keeping the + # a ValueError, which finish_sync then ignored — keeping the # upstream's rate-limit bucket full indefinitely. if response.status_code == 429: from services.mesh.mesh_infonet_sync_support import ( @@ -1680,8 +1680,8 @@ def _hydrate_gate_store_from_chain(events: list[dict]) -> int: """Copy any gate_message chain events into the local gate_store for read/decrypt. Only events that are resident in the local infonet (accepted or already - present) are hydrated. The canonical infonet-resident event is used ├óΓé¼ΓÇ¥ - never the raw batch event ├óΓé¼ΓÇ¥ so a forged batch entry carrying a valid + present) are hydrated. The canonical infonet-resident event is used — + never the raw batch event — so a forged batch entry carrying a valid event_id but attacker-chosen payload cannot pollute gate_store. """ import copy @@ -1766,7 +1766,7 @@ def _sync_from_peer( Returns ``(ok, error, forked, retry_after_s)``. The fourth tuple element is non-zero only when the peer responded with HTTP 429 - and supplied a parseable ``Retry-After`` header ΓÇö see the typed + and supplied a parseable ``Retry-After`` header — see the typed ``PeerSyncRateLimited`` exception in mesh_infonet_sync_support.py. Callers should pass that value to ``finish_sync(retry_after_s=...)`` so the next attempt actually waits. @@ -1909,7 +1909,7 @@ def _run_public_sync_cycle() -> SyncWorkerState: except PeerSyncHTTPError as exc: # _sync_from_peer catches PeerSyncRateLimited internally (4-tuple # path for 429 with Retry-After). Other non-200 statuses surface - # here as PeerSyncHTTPError ΓÇö pull retry_after_s + status off it + # here as PeerSyncHTTPError — pull retry_after_s + status off it # so the cooldown calculation below can honor server hints even # for non-429 throttling responses. ok = False @@ -1974,7 +1974,7 @@ def _run_public_sync_cycle() -> SyncWorkerState: failure_backoff_s=failure_backoff_s, # 429 retry-storm fix: when the peer returned HTTP 429 with # a Retry-After header, finish_sync uses max(exponential, - # retry_after) for next_sync_due_at ΓÇö so we actually wait + # retry_after) for next_sync_due_at — so we actually wait # the time the upstream asked for instead of hammering # every 60s and keeping its rate-limit bucket full forever. retry_after_s=retry_after_s, @@ -2148,13 +2148,13 @@ def _start_infonet_node_runtime(reason: str = "startup") -> None: logger.warning(f"Node bootstrap runtime failed to initialize: {e}") -# ├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼ Background HTTP Peer Push Worker ├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼ +# ─── Background HTTP Peer Push Worker ──────────────────────────────────── # Runs alongside the sync loop. Every PUSH_INTERVAL seconds, batches new # Infonet events and sends them via HMAC-authenticated POST to push peers. _PEER_PUSH_INTERVAL_S = 10 _PEER_PUSH_BATCH_SIZE = 50 -_peer_push_last_index: dict[str, int] = {} # peer_url ├óΓÇáΓÇÖ last pushed event index +_peer_push_last_index: dict[str, int] = {} # peer_url → last pushed event index _INFONET_SYNC_RATE_LIMIT = "600/minute" @@ -2174,7 +2174,7 @@ def _http_peer_push_loop() -> None: # legacy global MESH_PEER_PUSH_SECRET path and the per-peer # MESH_PEER_SECRETS map. The per-peer skip happens below # ("if not peer_key: continue"), so we don't gate the whole - # loop on the global secret being set ΓÇö an install that only + # loop on the global secret being set — an install that only # configures per-peer secrets is now valid. peers = _filter_infonet_peer_urls(authenticated_push_peer_urls()) @@ -2234,7 +2234,7 @@ def _http_peer_push_loop() -> None: _peer_push_last_index[normalized] = last_idx + len(batch) logger.info( f"Pushed {len(batch)} event(s) to {normalized[:40]} " - f"(idx {last_idx}├óΓÇáΓÇÖ{last_idx + len(batch)})" + f"(idx {last_idx}→{last_idx + len(batch)})" ) else: logger.warning(f"Peer push to {normalized[:40]} returned {resp.status_code}") @@ -2262,13 +2262,13 @@ def _swarm_manifest_pull_loop() -> None: _NODE_SYNC_STOP.wait(max(30, interval_s)) -# ├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼ Background Gate Message Pull Worker ├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼ +# ─── Background Gate Message Pull Worker ───────────────────────────────── # Periodically pulls gate events from relay peers that this node is missing. # Complements the push loop: push sends OUR events to peers, pull fetches # THEIR events from peers (needed when this node is behind NAT). _GATE_PULL_INTERVAL_S = 10 -_gate_pull_last_count: dict[str, dict[str, int]] = {} # peer ├óΓÇáΓÇÖ {gate_id ├óΓÇáΓÇÖ known count} +_gate_pull_last_count: dict[str, dict[str, int]] = {} # peer → {gate_id → known count} def _http_gate_pull_loop() -> None: @@ -2405,9 +2405,9 @@ def _http_gate_pull_loop() -> None: -# ├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼ Background Gate Message Push Worker ├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼ +# ─── Background Gate Message Push Worker ───────────────────────────────── -_gate_push_last_count: dict[str, dict[str, int]] = {} # peer ├óΓÇáΓÇÖ {gate_id ├óΓÇáΓÇÖ count} +_gate_push_last_count: dict[str, dict[str, int]] = {} # peer → {gate_id → count} def _http_gate_push_loop() -> None: @@ -2750,9 +2750,9 @@ async def lifespan(app: FastAPI): validate_env(strict=not _MESH_ONLY) if _MESH_ONLY: - logger.info("MESH_ONLY enabled ├óΓé¼ΓÇ¥ skipping global data fetchers/schedulers.") + logger.info("MESH_ONLY enabled — skipping global data fetchers/schedulers.") else: - # Start AIS stream first ├óΓé¼ΓÇ¥ it loads the disk cache (instant ships) then + # Start AIS stream first — it loads the disk cache (instant ships) then # begins accumulating live vessel data via WebSocket in the background. start_ais_stream() @@ -2760,7 +2760,7 @@ async def lifespan(app: FastAPI): # in _scheduler_loop, so we do NOT call it again in the preload thread. start_carrier_tracker() - # Start SIGINT grid eagerly ├óΓé¼ΓÇ¥ APRS-IS TCP + Meshtastic MQTT connections + # Start SIGINT grid eagerly — APRS-IS TCP + Meshtastic MQTT connections # take a few seconds to handshake and start receiving packets. By starting # now, the bridges are already accumulating signals by the time the first # fetch_sigint() reads them during the preload cycle. @@ -2869,7 +2869,7 @@ async def lifespan(app: FastAPI): delay_s = float(os.environ.get("SHADOWBROKER_STARTUP_PRELOAD_DELAY_S", "2.0") or 0) if delay_s > 0: time.sleep(delay_s) - logger.info("=== PRELOADING DATA (background ├óΓé¼ΓÇ¥ server already accepting requests) ===") + logger.info("=== PRELOADING DATA (background — server already accepting requests) ===") try: update_all_data(startup_mode=True) logger.info("=== PRELOAD COMPLETE ===") @@ -2883,7 +2883,7 @@ async def lifespan(app: FastAPI): try: from services.tor_hidden_service import tor_service, HOSTNAME_PATH if HOSTNAME_PATH.exists(): - logger.info("Previous Tor hidden service detected ├óΓé¼ΓÇ¥ auto-restarting...") + logger.info("Previous Tor hidden service detected — auto-restarting...") threading.Thread( target=tor_service.start, daemon=True ).start() @@ -3196,9 +3196,9 @@ def _trusted_gate_reply_to(event: dict) -> str: def _derive_anon_handle(node_id: str, gate_id: str) -> str: """Derive a stable per-session, per-gate anonymous display handle. - Same node_id + same gate ΓåÆ same handle for every message that session + Same node_id + same gate → same handle for every message that session posts (lets other members follow a conversation thread). Different - session (anon re-enters ΓåÆ new node_id) ΓåÆ new handle. Different gate ΓåÆ + session (anon re-enters → new node_id) → new handle. Different gate → different handle for the same session (prevents cross-gate linking). Not reversible: the handle is HMAC-SHA256(node_id, gate_id) truncated to 4 hex chars (~16 bits), which is enough to tell sessions apart in @@ -3239,7 +3239,7 @@ def _strip_gate_identity_member(event: dict, *, envelope_policy: str = "envelope "transport_lock": str(payload.get("transport_lock", "") or ""), # gate_envelope is AES-256-GCM ciphertext encrypted under the gate's # domain key (gate_secret). Only members who hold the gate_secret - # can decrypt it ΓÇö so exposing the ciphertext itself to members is + # can decrypt it — so exposing the ciphertext itself to members is # safe, and it's REQUIRED for the envelope_always decrypt path that # gives members durable re-readable history. envelope_hash is the # cryptographic binding (SHA-256 of gate_envelope) the decrypt path @@ -3302,7 +3302,7 @@ def _strip_gate_identity_privileged(event: dict) -> dict: def _strip_gate_identity(event: dict) -> dict: - """Legacy alias ├óΓé¼ΓÇ¥ defaults to member (narrowed) view.""" + """Legacy alias — defaults to member (narrowed) view.""" return _strip_gate_identity_member(event) @@ -3484,7 +3484,7 @@ def _verify_gate_access(request: Request, gate_id: str) -> str: return "" -# ├óΓÇ¥Γé¼├óΓÇ¥Γé¼ Non-hostile transport auto-upgrade ├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼ +# ── Non-hostile transport auto-upgrade ──────────────────────────────── # # The mesh/wormhole middleware can try to bring the wormhole supervisor # up in the background when a user hits a tier-gated route on a weak @@ -3751,8 +3751,8 @@ async def enforce_high_privacy_mesh(request: Request, call_next): # background and return an ok:True "preparing" response # (202 Accepted) so the client shows a spinner rather # than an approval dialog. The request itself is NOT - # forwarded to the handler ΓÇö the tier is too low for the - # route's required privacy ΓÇö but the client can poll and + # forwarded to the handler — the tier is too low for the + # route's required privacy — but the client can poll and # retry transparently once the lane warms up. try: upgraded = await _try_transparent_transport_upgrade() @@ -3785,7 +3785,7 @@ async def enforce_high_privacy_mesh(request: Request, call_next): data = read_wormhole_settings() # Tor-style: if the user selected high privacy but Wormhole # isn't enabled yet, just turn it on and kick off warmup. - # Don't block the request on the upgrade ΓÇö the transport + # Don't block the request on the upgrade — the transport # manager will converge in the background. if ( private_mesh_path @@ -3808,7 +3808,7 @@ async def enforce_high_privacy_mesh(request: Request, call_next): or _is_anonymous_dm_action_path(path, request.method) or _is_anonymous_wormhole_gate_admin_path(path, request.method) ): - # Tor-style: anonymous mode is on ΓåÆ do whatever is required for + # Tor-style: anonymous mode is on → do whatever is required for # it to function. Auto-enable Wormhole if off, and schedule # hidden-transport warmup WITHOUT blocking this request. The # transport manager converges in the background; the user sees @@ -3972,7 +3972,7 @@ def _queue_viirs_change_refresh() -> None: @limiter.limit("60/minute") async def update_viewport(vp: ViewportUpdate, request: Request): # noqa: ARG001 """Receive frontend map bounds. AIS stream stays global so open-ocean - vessels are never dropped ├óΓé¼ΓÇ¥ the frontend worker handles viewport culling.""" + vessels are never dropped — the frontend worker handles viewport culling.""" return {"status": "ok"} @@ -4140,7 +4140,7 @@ async def nearest_sdr( return find_nearest_kiwisdr(lat, lng, kiwisdr_data) -# ├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼ Per-Identity Throttle State ├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼ +# ─── Per-Identity Throttle State ────────────────────────────────────────── # In-memory: {node_id: {"last_send": timestamp, "daily_count": int, "daily_reset": timestamp}} # Bounded to 10000 entries with 24hr TTL to prevent unbounded memory growth _node_throttle: TTLCache = TTLCache(maxsize=10000, ttl=86400) @@ -4224,7 +4224,7 @@ def _check_throttle( def _check_gate_post_cooldown(sender_id: str, gate_id: str) -> tuple[bool, str]: - """Check cooldown ├óΓé¼ΓÇ¥ does NOT record it. Call _record_gate_post_cooldown() after success.""" + """Check cooldown — does NOT record it. Call _record_gate_post_cooldown() after success.""" gate_key = str(gate_id or "").strip().lower() sender_key = str(sender_id or "").strip() if not gate_key or not sender_key: @@ -4426,7 +4426,7 @@ def _prepared_signed_write(request: Request): @limiter.limit("10/minute") @requires_signed_write(kind=SignedWriteKind.MESH_SEND) async def mesh_send(request: Request): - """Unified mesh message endpoint ├óΓé¼ΓÇ¥ auto-routes via optimal transport. + """Unified mesh message endpoint — auto-routes via optimal transport. Body: { destination, message, priority?, channel?, node_id?, credentials? } The router picks APRS, Meshtastic, or Internet based on gate logic. @@ -4438,7 +4438,7 @@ async def mesh_send(request: Request): if not destination or not message: return {"ok": False, "detail": "Missing required fields: destination, message"} - # ├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼ Byte limit enforcement ├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼ + # ─── Byte limit enforcement ─────────────────────────────────── payload_bytes = len(message.encode("utf-8")) payload_type = body.get("payload_type", "text") max_bytes = _BYTE_LIMITS.get(payload_type, 200) @@ -4448,7 +4448,7 @@ async def mesh_send(request: Request): "detail": f"Message too long ({payload_bytes} bytes). Maximum: {max_bytes} bytes for {payload_type} messages.", } - # ├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼ Signature verification & node registration ├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼ + # ─── Signature verification & node registration ────────────── node_id = body.get("node_id", body.get("sender_id", "anonymous")) public_key = body.get("public_key", "") public_key_algo = body.get("public_key_algo", "") @@ -4471,9 +4471,9 @@ async def mesh_send(request: Request): reputation_ledger.register_node(node_id, public_key, public_key_algo) except Exception: - pass # Non-critical ├óΓé¼ΓÇ¥ don't block sends if reputation module fails + pass # Non-critical — don't block sends if reputation module fails - # ├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼ Per-identity throttle ├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼ + # ─── Per-identity throttle ──────────────────────────────────── priority_str = signed_payload["priority"] transport_lock = str(body.get("transport_lock", "") or "").lower() throttle_ok, throttle_reason = _check_throttle(node_id, priority_str, transport_lock) @@ -4496,7 +4496,7 @@ async def mesh_send(request: Request): } priority = priority_map.get(priority_str, Priority.NORMAL) - # ├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼ C-1 fix: compute trust_tier from Wormhole state ├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼ + # ─── C-1 fix: compute trust_tier from Wormhole state ─────── from services.wormhole_supervisor import get_transport_tier computed_tier = get_transport_tier() @@ -4512,7 +4512,7 @@ async def mesh_send(request: Request): ) credentials = body.get("credentials", {}) - # ├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼ C-2 fix: enforce tier before transport_lock dispatch ├óΓÇ¥Γé¼├óΓÇ¥Γé¼ + # ─── C-2 fix: enforce tier before transport_lock dispatch ── private_tier = str(envelope.trust_tier or "").startswith("private_") if transport_lock == "meshtastic": if private_tier: @@ -4548,7 +4548,7 @@ async def mesh_send(request: Request): results = mesh_router.route(envelope, credentials) any_ok = any(r.ok for r in results) - # ├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼ Mirror to Meshtastic bridge feed ├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼ + # ─── Mirror to Meshtastic bridge feed ──────────────────────── # The MQTT broker won't echo our own publishes back to our subscriber, so # inject successfully-sent channel broadcasts into the bridge directly. # Node-targeted packets must not appear in the public channel feed. @@ -4720,14 +4720,14 @@ async def mesh_messages( @app.get("/api/mesh/channels") @limiter.limit("30/minute") async def mesh_channels(request: Request): - """Get Meshtastic channel population stats ├óΓé¼ΓÇ¥ nodes per region/channel.""" + """Get Meshtastic channel population stats — nodes per region/channel.""" stats = get_latest_data().get("mesh_channel_stats", {}) return stats -# ├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼ Reputation Endpoints ├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼ +# ─── Reputation Endpoints ───────────────────────────────────────────────── -# Cached root node_id ├óΓé¼ΓÇ¥ avoids 5 encrypted disk reads per vote. +# Cached root node_id — avoids 5 encrypted disk reads per vote. _root_node_id_cache: dict[str, object] = {"value": None, "ts": 0.0} _ROOT_NODE_ID_TTL = 30.0 # seconds @@ -4784,7 +4784,7 @@ async def mesh_vote(request: Request): vote_payload = {"target_id": target_id, "vote": vote, "gate": gate} # Resolve stable local operator ID for duplicate-vote prevention. - # Personas generate unique keypairs, so voter_id alone is insufficient ├óΓé¼ΓÇ¥ + # Personas generate unique keypairs, so voter_id alone is insufficient — # use the root identity's node_id as a stable anchor so switching personas # doesn't let the same operator vote multiple times on the same post. stable_voter_id = voter_id @@ -5073,7 +5073,7 @@ async def mesh_identity_revoke(request: Request): return {"ok": True, "detail": "Identity revoked"} -# ├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼ Gate Endpoints ├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼ +# ─── Gate Endpoints ─────────────────────────────────────────────────────── @app.post("/api/mesh/gate/create") @@ -5144,7 +5144,7 @@ async def gate_create(request: Request): @app.get("/api/mesh/gate/list") @limiter.limit("30/minute") async def gate_list(request: Request): - """List all known gates (public catalog ├óΓé¼ΓÇ¥ secrets are never included).""" + """List all known gates (public catalog — secrets are never included).""" from services.mesh.mesh_reputation import gate_manager return {"gates": gate_manager.list_gates()} @@ -5247,7 +5247,7 @@ def _submit_gate_message_envelope(request: Request, gate_id: str, body: dict[str payload_ok, payload_reason = validate_event_payload("gate_message", gate_payload) if not payload_ok: return {"ok": False, "detail": payload_reason} - # gate_envelope is not part of the signed payload ├óΓé¼ΓÇ¥ envelope_hash binds it. + # gate_envelope is not part of the signed payload — envelope_hash binds it. # reply_to is signed for new compose flows; if only the legacy no-reply_to # signature verifies, strip it rather than accepting unauthenticated # threading metadata. @@ -5397,13 +5397,13 @@ def _submit_gate_message_envelope(request: Request, gate_id: str, body: dict[str ) -# ├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼ Infonet Endpoints ├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼ +# ─── Infonet Endpoints ─────────────────────────────────────────────────── @app.get("/api/mesh/infonet/status") @limiter.limit("30/minute") async def infonet_status(request: Request, verify_signatures: bool = False): - """Get Infonet metadata ├óΓé¼ΓÇ¥ event counts, head hash, chain size.""" + """Get Infonet metadata — event counts, head hash, chain size.""" from services.mesh.mesh_hashchain import infonet from services.wormhole_supervisor import get_wormhole_state @@ -5582,7 +5582,7 @@ async def mesh_metrics(request: Request): ok, detail = _check_scoped_auth(request, "mesh.audit") if not ok: if detail == "insufficient scope": - raise HTTPException(status_code=403, detail="Forbidden ├óΓé¼ΓÇ¥ insufficient scope") + raise HTTPException(status_code=403, detail="Forbidden — insufficient scope") raise HTTPException(status_code=403, detail=detail) return snapshot() @@ -5982,7 +5982,7 @@ async def gate_peer_pull(request: Request): # --------------------------------------------------------------------------- -# Peer Management API ├óΓé¼ΓÇ¥ operator endpoints for adding / removing / listing +# Peer Management API — operator endpoints for adding / removing / listing # peers without editing peer_store.json by hand. # --------------------------------------------------------------------------- @@ -6039,7 +6039,7 @@ async def add_peer(request: Request): if not transport: transport = peer_transport_kind(peer_url) if not transport: - return {"ok": False, "detail": "Cannot determine transport for peer_url ├óΓé¼ΓÇ¥ provide transport explicitly"} + return {"ok": False, "detail": "Cannot determine transport for peer_url — provide transport explicitly"} label = str(body.get("label", "") or "").strip() role = str(body.get("role", "") or "").strip().lower() or "relay" @@ -6416,7 +6416,7 @@ async def infonet_events_by_type( } -# ├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼ Oracle Endpoints ├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼ +# ─── Oracle Endpoints ───────────────────────────────────────────────────── @app.post("/api/mesh/oracle/predict") @@ -6426,8 +6426,8 @@ async def oracle_predict(request: Request): """Place a prediction on a market outcome. FINAL decision. Body: {node_id, market_title, side, stake_amount?: number} - - stake_amount = 0 or omitted ├óΓÇáΓÇÖ FREE PICK (earn rep if correct) - - stake_amount > 0 ├óΓÇáΓÇÖ STAKE REP (risk rep, split loser pool if correct) + - stake_amount = 0 or omitted → FREE PICK (earn rep if correct) + - stake_amount > 0 → STAKE REP (risk rep, split loser pool if correct) - side can be "yes"/"no" or an outcome name for multi-outcome markets """ from services.mesh.mesh_oracle import oracle_ledger @@ -6466,7 +6466,7 @@ async def oracle_predict(request: Request): if m.get("title", "").lower() == market_title.lower(): matched = m break - # Fuzzy fallback ├óΓé¼ΓÇ¥ partial match + # Fuzzy fallback — partial match if not matched: for m in markets: if market_title.lower() in m.get("title", "").lower(): @@ -6497,13 +6497,13 @@ async def oracle_predict(request: Request): probability = 100.0 - probability if stake_amount > 0: - # STAKED prediction ├óΓé¼ΓÇ¥ risk rep for bigger reward + # STAKED prediction — risk rep for bigger reward ok, detail = oracle_ledger.place_market_stake( node_id, matched["title"], side, stake_amount, probability ) mode = "staked" else: - # FREE prediction ├óΓé¼ΓÇ¥ no rep risked + # FREE prediction — no rep risked ok, detail = oracle_ledger.place_prediction(node_id, matched["title"], side, probability) mode = "free" @@ -6726,7 +6726,7 @@ async def oracle_resolve(request: Request): @app.get("/api/mesh/oracle/consensus") @limiter.limit("30/minute") async def oracle_consensus(request: Request, market_title: str = ""): - """Get network consensus for a market ├óΓé¼ΓÇ¥ picks + staked rep per side.""" + """Get network consensus for a market — picks + staked rep per side.""" from services.mesh.mesh_oracle import oracle_ledger if not market_title: @@ -6815,7 +6815,7 @@ async def oracle_stakes_for_message(request: Request, message_id: str): @app.get("/api/mesh/oracle/profile") @limiter.limit("30/minute") async def oracle_profile(request: Request, node_id: str = ""): - """Get full oracle profile ├óΓé¼ΓÇ¥ rep, prediction history, win rate, farming score.""" + """Get full oracle profile — rep, prediction history, win rate, farming score.""" from services.mesh.mesh_oracle import oracle_ledger if not node_id: @@ -6853,7 +6853,7 @@ async def oracle_resolve_stakes(request: Request): return {"ok": True, "resolutions": resolutions, "count": len(resolutions)} -# ├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼ Encrypted DM Relay (Dead Drop) ├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼ +# ─── Encrypted DM Relay (Dead Drop) ─────────────────────────────────────── def _secure_dm_enabled() -> bool: @@ -6887,7 +6887,7 @@ def _anonymous_dm_hidden_transport_requested() -> bool: is *ready* yet. Use this (not the ``_enforced`` variant) for *protective* logic that must - keep stated privacy intent honored during warmup ΓÇö e.g., skipping direct + keep stated privacy intent honored during warmup — e.g., skipping direct RNS metadata lookups. ``_enforced`` is for claim/telemetry paths that report what is currently being honored. """ @@ -7165,7 +7165,7 @@ async def _dm_send_from_signed_request(request: Request): return {"ok": False, "detail": "DM timestamp is too far from current time"} if delivery_class not in ("request", "shared"): return {"ok": False, "detail": "delivery_class must be request or shared"} - # Contact requests are the first-contact handshake ΓÇö do not require prior verification. + # Contact requests are the first-contact handshake — do not require prior verification. if delivery_class == "shared": try: from services.mesh.mesh_wormhole_contacts import verified_first_contact_requirement @@ -7493,7 +7493,7 @@ async def _dm_count_secure_from_signed_request(request: Request): mailbox_keys = dm_relay.claim_mailbox_keys(agent_id, claims) relay_ids = dm_relay.claim_message_ids(agent_id, claims) direct_ids = set() - # Rec #9: requested (not merely enforced) ΓÇö skip direct-lane count probe + # Rec #9: requested (not merely enforced) — skip direct-lane count probe # as soon as anonymous mode is requested, even before ready converges. if not _anonymous_dm_hidden_transport_requested(): try: @@ -7594,7 +7594,7 @@ async def dm_get_pubkey( if key_bundle is None: # Invite handles are minted on the owner's node. When a remote peer # pastes a short address, resolve it across the private fleet before - # failing ΓÇö same path as prekey-bundle import. + # failing — same path as prekey-bundle import. from services.mesh.mesh_wormhole_prekey import fetch_dm_prekey_bundle preferred_lookup_peer = str(lookup_peer_url or "").strip().rstrip("/") @@ -8161,7 +8161,7 @@ async def debug_latest_data(request: Request): return list(get_latest_data().keys()) -# ├óΓÇ¥Γé¼├óΓÇ¥Γé¼ CCTV media proxy (bypass CORS for cross-origin video/image streams) ├óΓÇ¥Γé¼├óΓÇ¥Γé¼├óΓÇ¥Γé¼ +# ── CCTV media proxy (bypass CORS for cross-origin video/image streams) ─── _CCTV_PROXY_ALLOWED_HOSTS = { "s3-eu-west-1.amazonaws.com", # TfL JamCams "jamcams.tfl.gov.uk", @@ -8810,12 +8810,12 @@ def api_region_dossier( lat: float = Query(..., ge=-90, le=90), lng: float = Query(..., ge=-180, le=180), ): - """Sync def so FastAPI runs it in a threadpool ├óΓé¼ΓÇ¥ prevents blocking the event loop.""" + """Sync def so FastAPI runs it in a threadpool — prevents blocking the event loop.""" return get_region_dossier(lat, lng) # --------------------------------------------------------------------------- -# Geocoding ├óΓé¼ΓÇ¥ proxy to Nominatim with caching and proper headers +# Geocoding — proxy to Nominatim with caching and proper headers # --------------------------------------------------------------------------- from services.geocode import search_geocode, reverse_geocode @@ -8988,7 +8988,7 @@ async def api_sentinel_tile(request: Request): evalscript = evalscripts.get(preset, evalscripts["TRUE-COLOR"]) # Adaptive time range: wider window at lower zoom for better coverage. - # Sentinel-2 has 5-day revisit ├óΓé¼ΓÇ¥ a single day often has gaps. + # Sentinel-2 has 5-day revisit — a single day often has gaps. # At low zoom we mosaic over more days to fill gaps. from datetime import datetime as _dt, timedelta as _td @@ -9058,7 +9058,7 @@ async def api_sentinel_tile(request: Request): # --------------------------------------------------------------------------- -# API Settings ├óΓé¼ΓÇ¥ key registry & management +# API Settings — key registry & management # --------------------------------------------------------------------------- from services.api_settings import get_api_keys, get_env_path_info from services.shodan_connector import ( @@ -9133,7 +9133,7 @@ async def api_shodan_host(request: Request, body: ShodanHostRequest): # --------------------------------------------------------------------------- -# Finnhub ├óΓé¼ΓÇ¥ free market intelligence (quotes, congress trades, insider txns) +# Finnhub — free market intelligence (quotes, congress trades, insider txns) # --------------------------------------------------------------------------- from services.unusual_whales_connector import ( FinnhubConnectorError, @@ -9223,7 +9223,7 @@ async def api_reset_news_feeds(request: Request): # --------------------------------------------------------------------------- -# Wormhole Settings ├óΓé¼ΓÇ¥ local agent toggle +# Wormhole Settings — local agent toggle # --------------------------------------------------------------------------- from services.wormhole_settings import read_wormhole_settings, write_wormhole_settings from services.wormhole_status import read_wormhole_status @@ -9394,7 +9394,7 @@ class NodeSettingsUpdate(BaseModel): @limiter.limit("30/minute") async def api_get_node_settings(request: Request): """Issue #243 (tg12): node mode and participant state are - operational posture. Anonymous callers receive an empty stub ΓÇö + operational posture. Anonymous callers receive an empty stub — enough for the UI to know the endpoint exists but nothing fingerprintable. Authenticated callers see the full state. @@ -10098,7 +10098,7 @@ def decrypt_wormhole_dm_envelope( if str(current_tier or "").startswith("private_"): return { "ok": False, - "detail": "MLS format required in private transport mode ├óΓé¼ΓÇ¥ legacy DM decrypt blocked", + "detail": "MLS format required in private transport mode — legacy DM decrypt blocked", } if not _legacy_dm1_allowed(): return { @@ -10252,7 +10252,7 @@ async def api_wormhole_join(request: Request): ) # Enable node participation so the sync/push workers connect to peers. - # This is the voluntary opt-in ├óΓé¼ΓÇ¥ the node only joins the network when + # This is the voluntary opt-in — the node only joins the network when # the user explicitly opens the Wormhole. from services.node_settings import write_node_settings @@ -12101,7 +12101,7 @@ async def api_set_privacy_profile(request: Request, body: PrivacyProfileUpdate): # --------------------------------------------------------------------------- -# System ├óΓé¼ΓÇ¥ self-update +# System — self-update # --------------------------------------------------------------------------- from pathlib import Path from services.updater import perform_update, schedule_restart @@ -12126,7 +12126,7 @@ async def system_update(request: Request): status_code=500, media_type="application/json", ) - # Docker: skip restart ├óΓé¼ΓÇ¥ user must pull new images manually + # Docker: skip restart — user must pull new images manually if result.get("status") == "docker": return result # Schedule restart AFTER response flushes (2s delay) diff --git a/backend/services/config.py b/backend/services/config.py index cc83137..d22a910 100644 --- a/backend/services/config.py +++ b/backend/services/config.py @@ -1,4 +1,4 @@ -"""Typed configuration via pydantic-settings.""" +"""Typed configuration via pydantic-settings.""" from functools import lru_cache from pydantic_settings import BaseSettings, SettingsConfigDict @@ -32,7 +32,7 @@ class Settings(BaseSettings): MESH_RNS_ENABLED: bool = False MESH_ARTI_ENABLED: bool = False # When true, trust wormhole_status.json ready bit if the child process is - # alive ΓÇö avoids transport-tier flapping when /api/health probes time out + # alive — avoids transport-tier flapping when /api/health probes time out # under Tor load (common during live DM E2E). MESH_WORMHOLE_TRUST_FILE_READY: bool = False MESH_ARTI_SOCKS_PORT: int = 9050 @@ -81,7 +81,7 @@ class Settings(BaseSettings): MESH_PEER_PUSH_SECRET: str = "" # Issue #256 (tg12): optional per-peer HMAC secret map. Comma-separated # `url=secret` pairs. When a peer URL appears here, only that per-peer - # secret is accepted for it ΓÇö the global MESH_PEER_PUSH_SECRET above is + # secret is accepted for it — the global MESH_PEER_PUSH_SECRET above is # ignored for that specific URL. Single-peer installs and unmigrated # multi-peer installs leave this empty and behavior is unchanged. MESH_PEER_SECRETS: str = "" @@ -123,7 +123,7 @@ class Settings(BaseSettings): MESH_RNS_IBF_FAIL_THRESHOLD: int = 3 MESH_RNS_IBF_COOLDOWN_S: int = 120 MESH_VERIFY_INTERVAL_S: int = 600 - # MESH_VERIFY_SIGNATURES is intentionally removed ΓÇö the audit loop in main.py + # MESH_VERIFY_SIGNATURES is intentionally removed — the audit loop in main.py # always calls validate_chain_incremental(verify_signatures=True). Any value # set in the environment is ignored. MESH_DM_SECURE_MODE: bool = True @@ -145,14 +145,14 @@ class Settings(BaseSettings): # Anti-spam: cap on distinct UNACKED messages a single sender can have # parked in a single recipient's mailbox at any one time. Once the # recipient pulls (acks) a message, the sender's quota for that pair - # frees up. Default 2 ΓÇö a sender who wants to deliver more must wait + # frees up. Default 2 — a sender who wants to deliver more must wait # for the recipient to actually read the prior messages. # # This cap is enforced TWICE: once on the local deposit path (the # sender's own node refuses to spool the 3rd message) AND once on # the replication-acceptance path (honest peer relays refuse to # accept inbound replicas that would put them over the cap). The - # double enforcement makes the rule a NETWORK rule ΓÇö patching out + # double enforcement makes the rule a NETWORK rule — patching out # the local check on a hostile sender's relay doesn't let extras # propagate, because every honest peer enforces the same cap on # inbound replication. @@ -169,7 +169,7 @@ class Settings(BaseSettings): MESH_VOTER_BLIND_SALT_GRACE_DAYS: int = 30 MESH_DM_MAX_MSG_BYTES: int = 8192 MESH_DM_ALLOW_SENDER_SEAL: bool = False - # TTL for DH key and prekey bundle registrations ΓÇö stale entries are pruned. + # TTL for DH key and prekey bundle registrations — stale entries are pruned. MESH_DM_KEY_TTL_DAYS: int = 30 # TTL for invite-scoped prekey lookup aliases; shorter windows reduce # long-lived relay linkage between opaque lookup handles and agent IDs. @@ -177,7 +177,7 @@ class Settings(BaseSettings): # TTL for relay witness history; keep continuity metadata bounded instead # of relying on a hidden hardcoded retention window. MESH_DM_WITNESS_TTL_DAYS: int = 14 - # TTL for mailbox binding metadata ΓÇö shorter = smaller metadata footprint on disk. + # TTL for mailbox binding metadata — shorter = smaller metadata footprint on disk. MESH_DM_BINDING_TTL_DAYS: int = 3 # When False, mailbox bindings are memory-only (agents re-register on restart). # Enable explicitly only if restart continuity is worth persisting DM graph metadata. @@ -320,7 +320,7 @@ class Settings(BaseSettings): # Second explicit opt-in for private-tier clearnet fallback. Without this # acknowledgement, "allow" remains requested but not effective. MESH_PRIVATE_CLEARNET_FALLBACK_ACKNOWLEDGE: bool = False - # Meshtastic MQTT bridge ΓÇö disabled by default to avoid hammering the + # Meshtastic MQTT bridge — disabled by default to avoid hammering the # public broker. Users opt in explicitly. MESH_MQTT_ENABLED: bool = False # Meshtastic MQTT broker credentials (defaults match public firmware). @@ -328,7 +328,7 @@ class Settings(BaseSettings): MESH_MQTT_PORT: int = 1883 MESH_MQTT_USER: str = "meshdev" MESH_MQTT_PASS: str = "large4cats" - # Hex-encoded PSK ΓÇö empty string means use the default LongFast key. + # Hex-encoded PSK — empty string means use the default LongFast key. # Must decode to exactly 16 or 32 bytes when set. MESH_MQTT_PSK: str = "" # Optional operator-provided Meshtastic node ID (e.g. "!abcd1234") included @@ -351,16 +351,16 @@ class Settings(BaseSettings): OPERATOR_HANDLE: str = "" # SAR (Synthetic Aperture Radar) data layer - # Mode A ΓÇö free catalog metadata, no account, default-on + # Mode A — free catalog metadata, no account, default-on MESH_SAR_CATALOG_ENABLED: bool = True - # Mode B ΓÇö free pre-processed anomalies (OPERA / EGMS / GFM / EMS / UNOSAT) + # Mode B — free pre-processed anomalies (OPERA / EGMS / GFM / EMS / UNOSAT) # Two-step opt-in: must be "allow" AND _ACKNOWLEDGE must be true MESH_SAR_PRODUCTS_FETCH: str = "block" MESH_SAR_PRODUCTS_FETCH_ACKNOWLEDGE: bool = False - # NASA Earthdata Login (free) ΓÇö required for OPERA products + # NASA Earthdata Login (free) — required for OPERA products MESH_SAR_EARTHDATA_USER: str = "" MESH_SAR_EARTHDATA_TOKEN: str = "" - # Copernicus Data Space (free) ΓÇö required for EGMS / EMS products + # Copernicus Data Space (free) — required for EGMS / EMS products MESH_SAR_COPERNICUS_USER: str = "" MESH_SAR_COPERNICUS_TOKEN: str = "" # Whether OpenClaw agents may read/act on the SAR layer