Business → Treasury access reconciliation is done with ad-hoc syncAllFirmAccounts() calls bolted onto some mutation paths. Two paths that change access never reconcile:
FirmRequestServiceImpl.completeTransferProprietorship calls firms.updateProprietor(...) but never (a) reassigns the Treasury account owner or (b) re-syncs members/authorizers. Result: the new proprietor is locked out of their own firm account (not owner/member/authorizer → canAccessAccount false), and the old owner keeps ownership + access.FirmRoleServiceImpl.addRolePermission/removeRolePermission/deleteRole/renameRole change what current role-holders can do but never re-sync, so granting/revoking FINANCIAL/ADMIN on a role does not propagate to Treasury membership until an unrelated employment event or a manual /business account sync.ACCEPTED firm_transfer_requests rows matching exactly.TreasuryApi.reassignOwner).completeTransferProprietorship: after updateProprietor, reassign every live firm account's Treasury owner to the new proprietor and syncAllFirmAccounts(firmId) (adds new proprietor as member+authorizer, removes old owner if not a current employee).syncAllFirmAccounts(firmId) to the role/permission mutators (addRolePermission, removeRolePermission, deleteRole, renameRole).One-time fix for the 5 live firms (reassign owner → current proprietor, add as member+authorizer, drop the stale old owner). SQL drafted for review before running against prod.
/business account ...; the old owner cannot.