The result of that subtraction is a timedelta object.
A timedelta object has a total_seconds() method that reports its value in seconds. Divide it by 3600 to get hours (as a floating point value).
{{ (now() - state_attr('automation.write_hot_tub_log','last_triggered')).total_seconds() / 3600 }}
I feel the result is to be expected given that you just manually triggered the automation.
last_triggered represents the time when the automation started executing its action (it has already successfully processed its trigger and action).
If the automation references its last_triggered value in its trigger or condition it will be, what you expect, namely the last time it triggered (i.e. not just a moment ago but some time in the past). However, upon executing its action the value of last_triggered is updated to the latest trigger time (i.e merely a moment ago).
If you want something to report the elapsed hours since the automation executed, you can use a Template Sensor.
template:
- sensor:
- name: Hot Tub Elapsed Hours
state: "{{ (now() - state_attr('automation.write_hot_tub_log','last_triggered')).total_seconds() / 3600 }}"
However, if your goal is to have an action in automation.write_hot_tub_log reference its own previous value of last_triggered then you can’t use a Template Sensor (because it will get updated the moment the automation’s last_triggered is updated).
EDIT
FWIW, this might be of interest to you: