After /firm account setdefault NHSE <id> the account displays as default, but /paya business NHSE 1 still sends to the old account — the two resolution paths disagree.
Technical notes — In business-rian: FirmMapper.updateFirm only writes default_account_id when non-null and archiveFirm NULLs it; FirmTransactionServiceImpl.resolveAccountId returns default_account_id with a getAnyAccountId legacy fallback. Audit every reader/writer of default_account_id (the setdefault command, firm create, the /paya/deposit resolution) so they agree, and make resolveAccountId self-heal (re-point to a surviving account) or error clearly when unset. Likely the root cause of PAR-45.
Fixed on develop (business-rian @ 951e270), together with PAR-45.
Audit of default_account_id readers/writers
createFirm (sets it to the new account), setDefaultAccount, disbandFirm/archiveFirm (NULL it). All go through FirmMapper.updateFirm/archiveFirm.resolveAccountId (/paya, deposit, withdraw, pay*). Both read firm.default_account_id keyed by firm_id.getFirmsByNameCount counts firms regardless of archived, so a name can't be reused after disband — both paths always resolve the same firm_id.Two concrete fixes
setDefaultAccount was not @Transactional — the only mutation in FirmAccountServiceImpl without it (archiveAccount etc. all have it). Under mybatis-guice the managed-session commit hangs off @Transactional, so the write could fail to persist while the next read still showed the old value — the "two paths disagree" symptom. Now @Transactional.resolveAccountId now validates the default still points at a live owned account and self-heals to a surviving account (persisted via the new @Transactional FirmService.updateDefaultAccount) when stale/unset, else throws NoFirmAccountException. So display and resolution can't diverge even if a stale pointer lingers.Tests: FirmMapperIT.updateFirm_persistsDefaultAccountId locks the writer/reader round-trip at the SQL layer; unit tests cover the self-heal paths. Full suite + coverage gate green.
Moving from Triage → Pending Release alongside PAR-45.
Code context —
/firm account setdefaultpersistsdefault_account_id, but/paya businessstill routes to the old account, so the two resolution paths disagree. Inbusiness-rian:FirmMapper.updateFirmonly writesdefault_account_idwhen non-null andarchiveFirmNULLs it;FirmTransactionServiceImpl.resolveAccountIdreturnsdefault_account_idwith agetAnyAccountIdlegacy fallback.Fix: audit every reader/writer of
default_account_id(setdefault command, firm create, the/paya/deposit resolution) so they agree, and makeresolveAccountIdself-heal (re-point to a surviving account) or error clearly when it's unset. Likely the root cause of PAR-45.