Track each task individually. The current way to register a task is done is an attribute on a group, that attribute will be multi-valued
Document each task on wiki (including description, if it is a substantial task that takes a long time, and which versions it is for)
Each task will continue to have an integer label associated with it. Do not re-use a task number across versions. The wiki is the system of record to register an upgrade task number
Refactor the attribute assigns so that tasks which are definitely known to be done will be marked as done. Tasks which are not sure if they are done, will be run again (they should be idempotent)
Refactor logic for upgrade tasks so the logic is not in the UpgradeTask class. IF there is logic for a task there, put it in its own file
No database DDL incremental version upgrade should have DDL that is in an upgrade task (since the DDL incremental version upgrade is not idempotent and is inferior)
Never add another DDL incremental version, only use upgrade tasks
The upgrade task daemon should be scheduled deep in future (consistent with other similar jobs), so it is just run manually, it shouldnt need to be run in normal circumstances
On startup, if there is an upgrade task to be run (find out in one query), then use the same JVM locking mechanism that the incremental uses. Check if there is a task to run again after attaining the lock (in case another JVM already did it)
Upgrade tasks run at startup should log to the daemon daemon logs (i.e. the daemon is run on that JVM just like the daemon ran it)
Document how to re-run a task. i.e. just delete an attribute value.