Run cleanTaskName without adding depencies

To utilize the gradle build cache, gradle must have exclusive access to the output files.
In a project I work on files can also be generated by a GUI tool when the user tests the configuration so gradle is not exclusively used. The build system is slowly migrated to gradle, this is also a way to utilize the gradle cache for longer running operations.

To avoid OVERLAPPING_OUTPUTS when building if the output has been touched by tools outside gradle, the outputs must be cleaned on build.
If the base plugin is applied, the lifecycle cleanTaskName can be used. However, this is not logical when implementing and can give performance problem. See the annotated snippet below.

    String cleanTask(String s) {
        return 'clean' + s.substring(0,1).toUpperCase() + s.substring(1)
    }
void apply(Project project) {
        // get default lifecycle including clean tasks
        project.plugins.apply(BasePlugin)
  def a = project.tasks.register('a')
  def b = project.tasks.register('b')

a.configure {
//OK to set dependency here, no side effects
dependsOn cleanTask(name)
}

        //adding dependencies to 'cleanB' will configure cleanB and 'b'
        //regardless if 'b' is considered to be executed
// (this may be a side effect of project.tasks.named()
        project.tasks.named(cleanTask(b.name)).configure {
            dependsOn a
            onlyIf { a.get().getDidWork() }
        }

        genRteCacheTask.configure {
            dependsOn cleanTask(name)
            // This will also create cleanB, B
            onlyIf { project.tasks.named(cleanTask(name)).get().getDidWork() }
}
}

Dependencies could also have been set as following, but that adds yet another source line
a<-b; cleanB<-B; cleanB.mustRunAfter(a)

It is possible to get around the cleanB, b is always created by creating a custom task that cleans the outputs for b. But the dependency is the same and it seems better to use the clean tasks.

Is there any better way to force outputs to be deleted so outputs are not overlapping in this situation?

(I would also like some way to get gradle to ignore outputs and still create cache, but that is another question.)

I found kind of a workaround, abusing onlyIf{}
However, if the same task type is executed twice, a dummy task must be executed in between…
(similar used to force cache only by stashing outputs in onlyIf and restoring in doFirst)

I still would like to have a property to get gradle to ignore outputs and still execute, updating caches

   boolean deleteOutputs(Project project, TaskOutputs taskOutputs) {
        taskOutputs.getFiles().each { File f ->
            project.delete(f)
        }
        return true
    }

void apply(Project project) {
 def a = project.tasks.register('a', MyTask)
 def dummy = project.tasks.register('dummy')
  def b = project.tasks.register('b', MyTask)

a.configure {
  onlyIf{ deleteOutputs(project, outputs) }
}

dummy.configure {
  dependsOn a
  doLast {
    // This task must be inserted and actually do something for b to not detect overlapping outputs
  }
}

b.configure {
  dependsOn dummy
  onlyIf{ deleteOutputs(project, outputs) }
}

Edit: issue to disabling overlapping outputs