Changing an input value of execution phase when not invalidating configuration cache

I am developing a plugin allowing users to configure a random seed to obtain reproducible build artifacts. Like this:

myPlugin {
    seed = 123
}

However, sometimes users may not want to hardcode the random seed. For example, they may want to use the commit count:

myPlugin {
   seed = getCommitCount()
}

So far, we can set a ValueSource to obtain the commit count. But then, each time users commit, the configuration cache misses. However, the random seed only affect the execution phase. Thus I want to make the seed a “execution-phase-only” provider and write my plugin like:

myPlugin {
   seedProvider = { getCommitCount() }
}
class MyTask: DefaultTask() {
    init {
        outputs.upToDateWhen { !hasSeedChanged(seedProvider) }
    }
    @TaskAction
    fun run() { doTheJob(seedProvider) }
}

My current workaround works more like the following:

open class myPluginExtension {
   var seedProvider: () -> Int = { 0 }
}

open class MyTask: DefaultTask() {
    @get:Input
    val executionSeed: Property<Int>
    @Internal
    var seedProvider: (() -> Int)?

    @TaskAction
    fun run() { doTheJob(seedProvider.get()) }

    init {
        outputs.upToDateWhen { seedProvider?.invoke() == executionSeed.get() }
    }
}

open class MyPlugin: Plugin<Project>{
  fun apply(project: Project) {
    val ext = project.extensions.create("myPlugin", myPluginExtension::class.java)
    project.tasks.register("myTask", MyTask::class.java) {
      it.seed.set(ext.seedProvider())
      it.seedProvider = ext.seedProvider
    }
  }
}

But it’s kind of tricky. I would like to ask if there’re better solutions?