Polish account-creation flow: insertion point, user_id consistency, startup race

Three small fixes shaken out by live testing on aio-demo:

1. fava_client.add_account: when the target file has no Open directives
   yet (e.g. the empty accounts/users.beancount seed), append at end of
   file instead of inserting at index 0. Keeps the seed header comments
   at the top where they belong.

2. account_sync.sync_single_account_from_beancount: read the full user_id
   from Beancount metadata when present, fall back to the name-derived
   8-char prefix otherwise. crud.get_or_create_user_account writes the
   full 32-char user_id into Beancount metadata when creating per-user
   accounts; the sync function was only looking at the account name and
   returning the prefix, so the post-sync `WHERE user_id=:user_id` query
   in crud.py missed the row and fell through the UNIQUE-constraint
   recovery path. Three lines of warning noise per user-account creation.

3. tasks.wait_for_account_sync: await `wait_for_fava_client()` (new
   helper backed by an asyncio.Event in fava_client.py) before the first
   sync iteration. Previously the sync task started in libra_start()
   raced the fire-and-forget `_init_fava()` coroutine and reliably
   crashed the first run with "Fava client not initialized".

Refs: aiolabs/libra#28
This commit is contained in:
Padreug 2026-06-06 19:36:39 +02:00
commit 09a5d6ed55
3 changed files with 40 additions and 3 deletions

View file

@ -320,11 +320,20 @@ async def sync_single_account_from_beancount(account_name: str) -> bool:
# Create in Libra DB
account_type = infer_account_type_from_name(account_name)
user_id = extract_user_id_from_account_name(account_name)
# Prefer the full user_id stored in Beancount metadata (libra writes it
# when crud.get_or_create_user_account calls fava.add_account). Fall
# back to the name-derived 8-char prefix for accounts imported without
# metadata. This keeps user_id consistent with what the caller will
# query for, avoiding a churn cycle through the UNIQUE-constraint
# recovery path in crud.py.
description = None
meta_user_id = None
if "meta" in bc_account and isinstance(bc_account["meta"], dict):
description = bc_account["meta"].get("description")
meta_user_id = bc_account["meta"].get("user_id")
user_id = meta_user_id or extract_user_id_from_account_name(account_name)
await create_account(
CreateAccount(