Chained compute remotes always report checkPresent=False (cycle guard adds current key to ancestor set)
- Dominant language
- Python
- Stars
- 29
- Forks
- 5
- PR merge metrics
- No merged PRs in 30d
Description
Chained compute remotes break: a compute remote whose input is itself a
computed file (output of another compute remote) always reports
`checkPresent = False`, regardless of whether the input is actually
reachable.
```
> git -C main annex fsck --from=cr1 mid.txt # depth-1: works
fsck mid.txt (cr1) ok
> git -C main annex fsck --from=cr2 out.txt # depth-2: cr2 needs mid.txt, mid.txt computable via cr1
fsck out.txt (cr2)
** Failed to verify content of out.txt (cr2):
expected to be present, but its content is missing
```
Introduced together with the compute special remote in `10.20250320`
(commit 70cb93a66b "checkPresent of compute remote checks inputs are
available"). Code unchanged through `10.20260525` (current upstream).
Root cause
`Remote/Compute.hs:827-847`:
```haskell
availablecompute inputkeys deadset computeset k' rs'
| k' `elem` inputkeys = return False -- line 827-828
| …
| otherwise = do
cs <- getComputeStatesUnsorted rs' k'
anyM
(\computestate ->
all id <$> mapM
(\k'' -> hasinputs k'' (computeStateRemoteState computestate)
<|||> availablecompute (k':inputkeys) deadset computeset k' -- line 847
. RemoteStateHandle
=<< computeStateInputs computestate k''
)
(computeStateInputs computestate))
cs
```
The recursive call passes `k'` as BOTH the new ancestor (`k':inputkeys`) AND
the next-key argument. On the very next descent, `k' \`elem\` (k':inputkeys)`
is unconditionally `True`, so the recursion returns `False` before
`getComputeStatesUnsorted` ever runs on the upstream remote.
The `inputkeys` set's purpose is "ancestor outputs we're already trying to
compute" — adding the *current input* to it on the recursive descent is
incorrect.
Suggested fix: drop the `k':` prefix on line 847, leaving
`availablecompute inputkeys deadset computeset k' . RemoteStateHandle =<< …`.
Reproducer (POSIX shell, exits non-zero when bug fires)
See `reproducer-compute-cycle-depth.sh` — two compute programs chained, with
the depth-1 fsck as a positive control and depth-2 fsck as the failing case.
Version
```
Verified with: git-annex 10.20260421
Confirmed present in: 10.20260525 (Remote/Compute.hs untouched in the interim)
```
Contributor guide
No contributing guide indexed for this repository
Research direction
Start in Remote/Compute.hs around lines 827-847, then inspect reproducer-compute-cycle-depth.sh. Verify the cycle guard and recursive call against the issue's described ancestor-set behavior. Run the reproducer and confirm both the depth-1 control and chained depth-2 fsck succeed without the missing-content failure.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- haskell, shell
- Domain
- cli, tooling
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 85/100