refactor: rename extension identity to spirekeeper

Fork of satmachineadmin's v2-bitspire line into its own repo. Renames
both identifiers so this extension is fully independent of the original
satmachineadmin install (which remains in service):

  - extension id   satmachineadmin -> spirekeeper
    (router prefix, static path/static_url_for, module symbols, task
     names, templates dir, config/manifest paths)
  - database name  satoshimachine  -> spirekeeper
    (Database(ext_spirekeeper), all schema-qualified table refs)

Also resets versioning to 0.1.0, sets the display name + manifest to
spirekeeper/aiolabs, and fixes the placeholder pyproject description.
Historical aiolabs/satmachineadmin#N issue references in comments are
left pointing at the original repo where those issues live.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Padreug 2026-06-13 22:30:05 +02:00
commit a059e3f596
22 changed files with 242 additions and 242 deletions

View file

@ -45,7 +45,7 @@ from .crud import (
from .distribution import process_settlement
from .models import CreateDcaSettlementData, Machine
LISTENER_NAME = "ext_satmachineadmin"
LISTENER_NAME = "ext_spirekeeper"
# Holds strong refs to in-flight distribution tasks so Python's GC doesn't
# collect them mid-flight (asyncio.create_task only weakly references its
@ -58,7 +58,7 @@ async def wait_for_paid_invoices() -> None:
invoice_queue: asyncio.Queue = asyncio.Queue()
register_invoice_listener(invoice_queue, LISTENER_NAME)
logger.info(
"satmachineadmin v2: invoice listener registered as "
"spirekeeper v2: invoice listener registered as "
f"`{LISTENER_NAME}` — waiting for bitSpire settlements."
)
while True:
@ -67,7 +67,7 @@ async def wait_for_paid_invoices() -> None:
await _handle_payment(payment)
except Exception as exc: # listener must never die
logger.error(
f"satmachineadmin: error handling payment "
f"spirekeeper: error handling payment "
f"{payment.payment_hash[:12]}...: {exc}"
)
@ -169,12 +169,12 @@ async def _handle_payment(payment: Payment) -> None:
settlement = await create_settlement_idempotent(data, initial_status="pending")
if settlement is None:
logger.error(
f"satmachineadmin: failed to insert settlement for "
f"spirekeeper: failed to insert settlement for "
f"payment_hash={payment.payment_hash[:12]}..."
)
return
logger.info(
f"satmachineadmin: landed settlement {settlement.id} for "
f"spirekeeper: landed settlement {settlement.id} for "
f"machine={machine.machine_npub[:12]}... "
f"wire={data.wire_sats}sats principal={data.principal_sats}sats "
f"fee={data.fee_sats}sats "
@ -224,12 +224,12 @@ async def _record_rejected(payment: Payment, machine: Machine, exc: Exception) -
)
if rejected is None:
logger.error(
f"satmachineadmin: failed to insert rejected settlement for "
f"spirekeeper: failed to insert rejected settlement for "
f"payment_hash={payment.payment_hash[:12]}..."
)
return
logger.error(
f"satmachineadmin: rejected settlement {rejected.id} "
f"spirekeeper: rejected settlement {rejected.id} "
f"(machine={machine.machine_npub[:12]}..., "
f"payment_hash={payment.payment_hash[:12]}...): {exc}"
)
@ -245,7 +245,7 @@ async def _record_rejected(payment: Payment, machine: Machine, exc: Exception) -
# upserts cassette_configs via apply_bootstrap_state.
#
# v1 = one-shot per machine (ATM's meta.bootstrapPublishedAt makes the
# publish idempotent on ATM-side restart; satmachineadmin's apply_bootstrap_
# publish idempotent on ATM-side restart; spirekeeper's apply_bootstrap_
# state dedups on state_event_id for relay re-delivery).
#
# v2 (separate issue) = continuous reverse-channel consumer with a
@ -258,7 +258,7 @@ async def _record_rejected(payment: Payment, machine: Machine, exc: Exception) -
# websocket. The relay manager is the same singleton publish_to_atm uses,
# so add_subscription registers a filter against the same relay pool.
CASSETTE_BOOTSTRAP_SUB_ID = "satmachineadmin-cassette-bootstrap"
CASSETTE_BOOTSTRAP_SUB_ID = "spirekeeper-cassette-bootstrap"
_CASSETTE_POLL_INTERVAL_S = 2.0
_CASSETTE_BACKOFF_S = 30.0 # when nostrclient isn't installed yet
@ -280,7 +280,7 @@ async def wait_for_cassette_state_events() -> None:
- apply_bootstrap_state errors log + skip
"""
logger.info(
"satmachineadmin v2: cassette bootstrap consumer starting "
"spirekeeper v2: cassette bootstrap consumer starting "
f"(sub_id={CASSETTE_BOOTSTRAP_SUB_ID})"
)
current_filter_key: str | None = None
@ -290,7 +290,7 @@ async def wait_for_cassette_state_events() -> None:
await asyncio.sleep(_CASSETTE_POLL_INTERVAL_S)
except _NostrclientUnavailable:
logger.warning(
"satmachineadmin: nostrclient extension not installed; "
"spirekeeper: nostrclient extension not installed; "
f"cassette bootstrap consumer sleeping {_CASSETTE_BACKOFF_S}s "
"before retry. Install + activate nostrclient on this "
"LNbits instance."
@ -299,7 +299,7 @@ async def wait_for_cassette_state_events() -> None:
await asyncio.sleep(_CASSETTE_BACKOFF_S)
except Exception as exc: # listener must never die
logger.error(
f"satmachineadmin: cassette consumer loop error (continuing): " f"{exc}"
f"spirekeeper: cassette consumer loop error (continuing): " f"{exc}"
)
await asyncio.sleep(_CASSETTE_POLL_INTERVAL_S)
@ -346,13 +346,13 @@ async def _cassette_consumer_tick(current_filter_key: str | None) -> str:
CASSETTE_BOOTSTRAP_SUB_ID, filters # type: ignore[arg-type]
)
logger.info(
"satmachineadmin: (re)registered cassette bootstrap "
"spirekeeper: (re)registered cassette bootstrap "
f"subscription with {len(d_tags)} d-tag(s)"
)
else:
nostr_client.relay_manager.close_subscription(CASSETTE_BOOTSTRAP_SUB_ID)
logger.info(
"satmachineadmin: no active machines; closed cassette "
"spirekeeper: no active machines; closed cassette "
"bootstrap subscription"
)
@ -368,7 +368,7 @@ async def _cassette_consumer_tick(current_filter_key: str | None) -> str:
)
except Exception as exc:
logger.warning(
f"satmachineadmin: cassette state event handler "
f"spirekeeper: cassette state event handler "
f"failed (skipping): {exc}"
)
@ -419,14 +419,14 @@ async def _handle_cassette_state_event(
event_obj = event_raw
else:
logger.warning(
f"satmachineadmin: cassette event of unexpected type "
f"spirekeeper: cassette event of unexpected type "
f"{type(event_raw).__name__}; skipping"
)
return
if not verify_event(event_obj):
logger.warning(
f"satmachineadmin: cassette state event sig verify failed "
f"spirekeeper: cassette state event sig verify failed "
f"(id={event_obj.get('id', '?')[:12]}...)"
)
return
@ -437,7 +437,7 @@ async def _handle_cassette_state_event(
# Unknown sender — could be relay noise or an attacker. Don't
# treat as our problem.
logger.warning(
f"satmachineadmin: cassette state event from unknown ATM "
f"spirekeeper: cassette state event from unknown ATM "
f"pubkey {sender_pubkey[:12]}... (not in dca_machines); "
"skipping"
)
@ -448,7 +448,7 @@ async def _handle_cassette_state_event(
except CassetteTransportError as exc:
# OperatorIdentityMissing / SignerUnavailable — log + skip.
logger.warning(
f"satmachineadmin: can't resolve signer for operator "
f"spirekeeper: can't resolve signer for operator "
f"{machine.operator_user_id[:8]}... (machine {machine.id}): "
f"{exc}"
)
@ -458,13 +458,13 @@ async def _handle_cassette_state_event(
payload = await decrypt_and_parse_state_event(event_obj, account, signer)
except CassetteEventTransientError as exc:
logger.info(
f"satmachineadmin: cassette state event for machine {machine.id} "
f"spirekeeper: cassette state event for machine {machine.id} "
f"hit a transient signer error (will retry next poll): {exc}"
)
return
except CassetteEventDecodeError as exc:
logger.warning(
f"satmachineadmin: cassette state event decode failed for "
f"spirekeeper: cassette state event decode failed for "
f"machine {machine.id} (id={event_obj.get('id', '?')[:12]}...): "
f"{exc}"
)
@ -479,12 +479,12 @@ async def _handle_cassette_state_event(
)
if applied:
logger.info(
f"satmachineadmin: applied bootstrap state event {event_id[:12]}... "
f"spirekeeper: applied bootstrap state event {event_id[:12]}... "
f"to machine {machine.id} ({len(payload.positions)} cassettes)"
)
else:
# Replay: event_id already on file. Normal on relay reconnect.
logger.debug(
f"satmachineadmin: cassette state event {event_id[:12]}... "
f"spirekeeper: cassette state event {event_id[:12]}... "
f"already applied to machine {machine.id} (replay no-op)"
)