Subject: Re: Potentially unnecessary redoing of targets

From: spacefrogg <[email-masked]>
Date: Mon, 12 Jan 2026 16:26:33 +0000

On 2026-01-12 15:12, Niklas Böhm wrote:
> Thanks for your response.  In general, I want to say that `2` is not 
> ood because `1` did not change after completion of `1.do`, hence we 
> would never have to start it.  The state when `2.do` is executing is in 
> fact not ood, but because we determined `1` to be ood (as 1.do that 
> changed), we run `2.do` anyways.  What I would suggest is to check, 
> once more, if the targets actually did change their content before 
> launching `2.do`.

Thanks, I see the case you are constructing.  But you are misjudging the 
task that you've given redo to do in the first place.

What I was trying to convey in my previous message was, in essence, 
that:
1) `redo-ifchange 1; redo-ifchange 2` and
2) `redo-ifchange 2`

are two separate cases that you are conflating with each other.  You are 
trying to turn case 2) into case 1), which is not what redo is about.

> I see that currently the problem is that the ood checking goes as 
> follows (with redo-ifchange -d):
> [48985] dbg  ood: 2 checking
> [48985] dbg  ood: 2 -> 2.do: checking
> [48985] dbg  ood: 2 -> 2.do: same inode
> [48985] dbg  ood: 2 -> 2.do: is source
> [48985] dbg  ood: 2 -> 1: checking
> [48985] dbg  ood: 2 -> 1: inode differs
> [48985] dbg  ood: 2 -> 1: same hash
> [48985] dbg  ood: . 1 checking
> [48985] dbg  ood: . 1 -> 1.do: checking
> [48985] dbg  ood: . 1 -> 1.do: inode differs
> [48985] dbg  ood: . 1 -> 1.do: hash differs
> [48985] dbg  ood: . 1: true
> [48985] dbg  ood: 2 -> 1: ood
> [48985] dbg  ood: 2: true

This is exactly as it should go, because what you are trying to execute 
is case 2).  In case 2), the only decision redo has to make is whether 
or not to execute `2.do`.  It does NOT decide whether to execute `1.do`. 
  As I explained in my last message, executing `2.do` could result in 
removing `1` (and by transitivity `1.do`) from its dependency graph 
entirely.  So, executing `1.do` just to find out whether you have to 
execute `2.do` or, even worse, cancelling the execution of `2.do` after 
the line `redo-ifchange 1` just because you've determined it no longer 
to be OOD, is the wrong move.

Prematurely executing `1.do` before `2.do` (which is precisely turning 
case 2) into case 1)) can be wrong for the following reasons:
- it could be removed from `2`'s dependency graph on the next run of 
`2.do`.  So it would be a waste of effort.
- it could be an after-dependency that is only to be executed after most 
of `2.do` has run (I use after-dependencies to collect dependencies from 
.tex files processes, for example).  So running it eagerly would 
potentially operate on old data.  And even if not, it is up to the user 
to place `redo-ifchange` calls in .do files.  By running them early, you 
virtually move them all to the front of the file, which could change the 
results in non-obvious ways.  This "feature" would also be very hard to 
communicate.

> I want to make the claim that `2` is not necessarily ood at that point, 
> as we could first redo `1` and then check if the output differs before 
> determining `2` to be ood.  As the build file `2.do` did not change, we 
> know that its dependencies do not change; hence in my opinion it is a 
> forgone conclusion to say that `2` is ood only because `1.do` has a 
> differing hash, but actually `1` itself does not.

This is where you are mixing things up.  Let me say the concluding 
statement of my last message again: The call that produced above trace 
was `redo-ifchange 2`.  It's purpose is to determine, whether or not to 
run `2.do`.  That's it.  For that decision, it uses the currently known 
dependency graph of `2` as a starting point.  According to this graph, 
`2` IS OOD and `2.do` must be run.  This does not mean anything with 
regards to `1` or `1.do`, even if the alteration of `1.do` was the 
cause.  But the only way to get rid of this outdated knowledge (that `1` 
is still a dependency of `2`) is to execute `2.do` and to find out.

> I'll admit that it might be an involved change in the code base and 
> will also make redo itself change its behavior (as you lose the 
> transitivity property for ood detection), but in my eyes it would be 
> correct to check the direct targets of the .do file, instead of 
> cascading the ood property.  This would also make the build system 
> minimal

As I was trying to clarify, such a system would be very different from 
redo and would not allow for free placement of `redo-ifchange ...` calls 
throughout .do files. Or, at least, these calls would have a different 
meaning, depending on whether you run the .do file for the first time or 
because it was determined to be OOD.

Believe me, I see, what you are trying to achieve, but with that change, 
the semantics of redo and redo-ifchange calls become weird and 
non-obvious.

Kind regards,
Michael