I have a scheduled job that populates a number of "denormalised" tables to present a simplified data structure for OData exposure so end users can write their own 'reports' in Excel. There are a number of these tables, with some tables benefiting from the aggregations performed in the population of earlier tables, so my approach to this has been to construct a batch controller task that
- instantiates a class to populate each table
- adds a task to the batch header using that population class
- creates dependencies between tasks
The issue I'm seeing is that tasks with multiple dependencies get left with a status of Didn't run, despite their dependencies Actual status appearing to meet the Expected status:

I've not managed to find much in the way of reference material for this status: there's one thread with no replies, and one with no definitive advice, so in case this description doesn't mean anything to people, the screenshot above of the batch job from comes from a minimal XPO I've put together. Relevant section of the controller class (pretty much all of it) is:
RunBaseBatch batchTask, postTask;
Set preReqTasksOne, preReqTasksTwo;
SetEnumerator se;
preReqTasksOne = new Set(Types::Class);
preReqTasksTwo = new Set(Types::Class);
batchHeader = BatchHeader::construct(this.parmCurrentBatch().BatchJobId);
info(strFmt('%1 Batch header constructed', DateTimeUtil::utcNow()));
//Call construct method for another batch class. Runtime tasks are removed on completion: most suitable for recurring tasks
//batchHeader.addRuntimeTask(LNPS_UnallocatedLedger_Populate::construct(), this.parmCurrentBatch().RecId);
//As opposed to Tasks that remain after completion: can be better for review/auditing
batchTask = LNPS_DependencyOne::construct();
batchHeader.addTask(batchTask, this.parmCurrentBatch().RecId);
preReqTasksOne.add(batchTask);
info(strFmt('%1 Task one added', DateTimeUtil::utcNow()));
batchTask = LNPS_DependencyTwo::construct();
batchHeader.addTask(batchTask, this.parmCurrentBatch().RecId);
preReqTasksTwo.add(batchTask);
info(strFmt('%1 Task two added', DateTimeUtil::utcNow()));
postTask = LNPS_DependentChild::construct();
batchHeader.addTask(postTask, this.parmCurrentBatch().RecId);
info(strFmt('%1 Child task added', DateTimeUtil::utcNow()));
//Enumerators are overkill in this instance where there's only one task in each set, but in true project, the prerequisite task has been split into multiple batch tasks for parallel execution
se = preReqTasksOne.getEnumerator();
while(se.moveNext())
{
batchTask = se.current();
batchHeader.addDependency(postTask, batchTask, BatchDependencyStatus::Finished);
}
info(strFmt('%1 Dependency set one added', DateTimeUtil::utcNow()));
se = preReqTasksTwo.getEnumerator();
while(se.moveNext())
{
batchTask = se.current();
batchHeader.addDependency(postTask, batchTask, BatchDependencyStatus::Finished);
}
info(strFmt('%1 Dependency set two added', DateTimeUtil::utcNow()));
info(strFmt('%1 All tasks added to batch header', DateTimeUtil::utcNow()));
batchHeader.save();
Any pointers to further reading material on the subject of dependencies, or specific advice on how I'm constructing my batch task, would be greatly appreciated.