Repository: syncthing/syncthing (language: go)

Issue:
IndexHandler can get stuck in an undesired loop
### Does your log mention database corruption?

No. Completely clean/new instances are also affected.

### Version info

 - Syncthing: 1.27.3 (but 1.27.2 was also tested)
 - OS: MacOS 14.3, but Ubuntu server 20.04 and Docker on a Debian Bookworm host also stumbled upon this issue
 - Browser: not relevant for this issue

### The problem

To start with the bad news, the exact trigger isn't very clear as it doesn't always occur using the same sequence. But it happens often enough, and is specific enough, to warrant a separate issue imo.

When debugging and digging into issues related to reverting receive-encrypted folders (I'm not sure if this is solely related to receive-encrypted folders), I stumbled upon odd behaviour. At given times the IndexHandler tends to get stuck in a (seemingly) nothing-to-send loop. To my understanding, this shouldn't really happen as eventually some wait-conditions should be triggered. The problem, when this happens, is that the affected Syncthing instance seems a bit ... unreliable. 

### Steps to reproduce:
1. Create a synced folder where one end is `receive encrypted`
2. On the receiving end, create a file or folder. Editing a properly synced encrypted file does not seem to trigger this (and overall works as expected)
3. As receive-encrypted folders don't have a watcher enabled per default, trigger a manual rescan
4. Revert the unexpected addition
5. (the GUI will get stuck with the fancy red button, but the file was removed regardless. This is what I tried to look into)
6. Pause the folder
7. Unpause the folder (this pause->unpause part sometimes has to be executed twice to trigger this)
8. Check the logs

### Observations

I enabled DB-logging and I added a custom log-line in the IndexHandler (in the `for err=nil`-loop) to see what sequences are involved. Apart from that added log-line, the main-branch was used (so no additional changes were involved).

The following will be repeated endlessly, around 4 times per second. 
```
[MRIW7] 2024/02/03 12:52:32.133462 set.go:170: DEBUG: afkhe-wfc4q Snapshot()
[MRIW7] 2024/02/03 12:52:32.133509 set.go:224: DEBUG: afkhe-wfc4q WithHaveSequence(26)
```

This was traced back to the function `(s *indexHandler) sendIndexTo`.

Since there are some mechanics involved to wait for the sequences to be updated (to my understanding), the added log line kept track of those;

1 - Base: fstat.Sequence: 25, s.prevSequence: 25
2/3 - After creating local file: fstat.S: 26, s.prevSequence: 26
4 - After reverting: fstat.Sequence: 27, s.prevSequence: 27
so far so good...
7 -  After pausing-unpausing: fstat.Sequence: 27, s.prevSequence: 25

Since the prevSequence is now 25 for some reason (obtained from the sending node?), it calls `withHaveSequence` with 25+1 and that doesn't result in anything and then nothing really happens in the remaining parts of the functions other than just repeating it.

### Logs
(filtered out unrelated verbose items, if it's too filtered I can always reproduce it again..:))
```
### Base state (7 correctly synced files)

[MRIW7] 2024/02/03 12:48:03.659362 indexhandler.go:170: DEBUG: fset.Sequence: 25, s.prevSequence: 25

### Adding locally added file -> trigger manual scan

[MRIW7] 2024/02/03 12:48:45.761563 folder.go:208: DEBUG: receiveencrypted/afkhe-wfc4q@0x14000fae400 Running something due to request
[MRIW7] 2024/02/03 12:48:45.761590 folder.go:437: DEBUG: receiveencrypted/afkhe-wfc4q@0x14000fae400 scanning
[MRIW7] 2024/02/03 12:48:45.764893 indexhandler.go:170: DEBUG: fset.Sequence: 26, s.prevSequence: 25
[MRIW7] 2024/02/03 12:48:46.016125 indexhandler.go:170: DEBUG: fset.Sequence: 26, s.prevSequence: 26

#### Revert folder

[MRIW7] 2024/02/03 12:51:31.609341 folder_recvenc.go:42: INFO: Reverting unexpected items in folder "receive-encrypted" (afkhe-wfc4q) (receive-encrypted)
[MRIW7] 2024/02/03 12:51:31.610282 indexhandler.go:170: DEBUG: fset.Sequence: 27, s.prevSequence: 26
[MRIW7] 2024/02/03 12:51:31.861526 indexhandler.go:170: DEBUG: fset.Sequence: 27, s.prevSequence: 27

### Pause -> unpause folder

[MRIW7] 2024/02/03 12:52:15.963436 model.go:560: INFO: Paused folder "receive-encrypted" (afkhe-wfc4q) (receiveencrypted)
[MRIW7] 2024/02/03 12:52:17.562143 model.go:413: INFO: Ready to synchronize "receive-encrypted" (afkhe-wfc4q) (receiveencrypted)
[MRIW7] 2024/02/03 12:52:17.562161 model.go:560: INFO: Unpaused folder "receive-encrypted" (afkhe-wfc4q) (receiveencrypted)
[MRIW7] 2024/02/03 12:52:17.562213 folder.go:153: DEBUG: receiveencrypted/afkhe-wfc4q@0x14001186400 starting
[MRIW7] 2024/02/03 12:52:17.562230 folder.go:204: DEBUG: receiveencrypted/afkhe-wfc4q@0x14001186400 Scanning due to timer
[MRIW7] 2024/02/03 12:52:17.562240 folder.go:437: DEBUG: receiveencrypted/afkhe-wfc4q@0x14001186400 scanning
[MRIW7] 2024/02/03 12:52:17.562349 set.go:170: DEBUG: afkhe-wfc4q Snapshot()
[MRIW7] 2024/02/03 12:52:17.562392 set.go:170: DEBUG: afkhe-wfc4q Snapshot()
[MRIW7] 2024/02/03 12:52:17.574885 set.go:268: DEBUG: afkhe-wfc4q Get(N.syncthing-enc)
[MRIW7] 2024/02/03 12:52:17.575051 set.go:268: DEBUG: afkhe-wfc4q Get(N.syncthing-enc/VG)
[MRIW7] 2024/02/03 12:52:17.575203 set.go:268: DEBUG: afkhe-wfc4q Get(N.syncthing-enc/VG/8HVMNU6FH03TMSM9DPA90T9IG)
[MRIW7] 2024/02/03 12:52:17.575246 set.go:268: DEBUG: afkhe-wfc4q Get(5.syncthing-enc)
[MRIW7] 2024/02/03 12:52:17.575566 set.go:268: DEBUG: afkhe-wfc4q Get(5.syncthing-enc/IJ)
[MRIW7] 2024/02/03 12:52:17.575713 set.go:268: DEBUG: afkhe-wfc4q Get(5.syncthing-enc/IJ/862VC8Q0BT386UAT3RNVDTCOG)
[MRIW7] 2024/02/03 12:52:17.575790 set.go:268: DEBUG: afkhe-wfc4q Get(R.syncthing-enc)
[MRIW7] 2024/02/03 12:52:17.575976 set.go:268: DEBUG: afkhe-wfc4q Get(R.syncthing-enc/VP)
[MRIW7] 2024/02/03 12:52:17.576117 set.go:268: DEBUG: afkhe-wfc4q Get(R.syncthing-enc/VP/EUE6927PBLUPBD2D2MIKHSU2G)
[MRIW7] 2024/02/03 12:52:17.576156 set.go:268: DEBUG: afkhe-wfc4q Get(Q.syncthing-enc)
[MRIW7] 2024/02/03 12:52:17.576279 set.go:268: DEBUG: afkhe-wfc4q Get(Q.syncthing-enc/F2)
[MRIW7] 2024/02/03 12:52:17.576423 set.go:268: DEBUG: afkhe-wfc4q Get(Q.syncthing-enc/F2/4HMCEK08PD9R5EQRDK91HH0QG)
[MRIW7] 2024/02/03 12:52:17.576458 set.go:268: DEBUG: afkhe-wfc4q Get(8.syncthing-enc)
[MRIW7] 2024/02/03 12:52:17.576579 set.go:268: DEBUG: afkhe-wfc4q Get(8.syncthing-enc/91)
[MRIW7] 2024/02/03 12:52:17.576761 set.go:268: DEBUG: afkhe-wfc4q Get(8.syncthing-enc/91/22BA4NEPD26QSL93I79CNG25G)
[MRIW7] 2024/02/03 12:52:17.576799 set.go:268: DEBUG: afkhe-wfc4q Get(4.syncthing-enc)
[MRIW7] 2024/02/03 12:52:17.576959 set.go:268: DEBUG: afkhe-wfc4q Get(4.syncthing-enc/0N)
[MRIW7] 2024/02/03 12:52:17.577092 set.go:268: DEBUG: afkhe-wfc4q Get(4.syncthing-enc/0N/1QD6P2MH40917OA3AEK4PH2CG)
[MRIW7] 2024/02/03 12:52:17.577129 set.go:268: DEBUG: afkhe-wfc4q Get(3.syncthing-enc)
[MRIW7] 2024/02/03 12:52:17.577252 set.go:268: DEBUG: afkhe-wfc4q Get(3.syncthing-enc/1T)
[MRIW7] 2024/02/03 12:52:17.577414 set.go:268: DEBUG: afkhe-wfc4q Get(3.syncthing-enc/1T/RPJCAJKAL413HDJQ5AV5EBEN0)
[MRIW7] 2024/02/03 12:52:17.577447 set.go:170: DEBUG: afkhe-wfc4q Snapshot()
[MRIW7] 2024/02/03 12:52:17.577471 set.go:234: DEBUG: afkhe-wfc4q WithPrefixedHaveTruncated(7777777-777777N-7777777-777777N-7777777-777777N-7777777-77777Q4, "")
[MRIW7] 2024/02/03 12:52:17.577906 folder.go:506: DEBUG: receiveencrypted/afkhe-wfc4q@0x14001186400 finished scanning, detected 0 changes
[MRIW7] 2024/02/03 12:52:17.577931 folder.go:925: INFO: Completed initial scan of receiveencrypted folder "receive-encrypted" (afkhe-wfc4q)
[MRIW7] 2024/02/03 12:52:17.577945 folder.go:312: DEBUG: receiveencrypted/afkhe-wfc4q@0x14001186400 next rescan in 18h21m40.125256037s
[MRIW7] 2024/02/03 12:52:17.577955 set.go:170: DEBUG: afkhe-wfc4q Snapshot()
[MRIW7] 2024/02/03 12:52:17.577968 set.go:192: DEBUG: afkhe-wfc4q WithNeed(7777777-777777N-7777777-777777N-7777777-777777N-7777777-77777Q4)
[MRIW7] 2024/02/03 12:52:17.584992 set.go:170: DEBUG: afkhe-wfc4q Snapshot()
[MRIW7] 2024/02/03 12:52:17.585010 progressemitter.go:285: DEBUG: progress emitter: bytes completed for afkhe-wfc4q: 0
[MRIW7] 2024/02/03 12:52:17.585805 set.go:170: DEBUG: afkhe-wfc4q Snapshot()
[MRIW7] 2024/02/03 12:52:17.585865 model.go:951: DEBUG: model@0x14000198180 Completion(I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU, "afkhe-wfc4q"): map[completion:100 globalBytes:7448 globalItems:7 needBytes:0 needDeletes:0 needItems:0 remoteState:unknown sequence:7]
[MRIW7] 2024/02/03 12:52:17.587487 set.go:170: DEBUG: afkhe-wfc4q Snapshot()
[MRIW7] 2024/02/03 12:52:17.587539 model.go:951: DEBUG: model@0x14000198180 Completion(I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU, "afkhe-wfc4q"): map[completion:100 globalBytes:7448 globalItems:7 needBytes:0 needDeletes:0 needItems:0 remoteState:unknown sequence:7]
[MRIW7] 2024/02/03 12:52:18.589779 set.go:170: DEBUG: afkhe-wfc4q Snapshot()
[MRIW7] 2024/02/03 12:52:18.589809 progressemitter.go:285: DEBUG: progress emitter: bytes completed for afkhe-wfc4q: 0
[MRIW7] 2024/02/03 12:52:21.069497 set.go:170: DEBUG: afkhe-wfc4q Snapshot()
[MRIW7] 2024/02/03 12:52:21.069556 progressemitter.go:285: DEBUG: progress emitter: bytes completed for afkhe-wfc4q: 0
[MRIW7] 2024/02/03 12:52:22.075274 set.go:385: DEBUG: afkhe-wfc4q IndexID(I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU)
[MRIW7] 2024/02/03 12:52:22.075306 set.go:385: DEBUG: afkhe-wfc4q IndexID(7777777-777777N-7777777-777777N-7777777-777777N-7777777-77777Q4)
[MRIW7] 2024/02/03 12:52:22.076146 model.go:1348: DEBUG: Registering folder afkhe-wfc4q for I6KAH76
[MRIW7] 2024/02/03 12:52:22.076168 indexhandler.go:531: DEBUG: Not resuming index handler for device I6KAH76 and folder afkhe-wfc4q as none is paused and there is no start info
[MRIW7] 2024/02/03 12:52:22.076521 set.go:385: DEBUG: afkhe-wfc4q IndexID(7777777-777777N-7777777-777777N-7777777-777777N-7777777-77777Q4)
[MRIW7] 2024/02/03 12:52:22.076654 indexhandler.go:59: DEBUG: Device I6KAH76 folder "receive-encrypted" (afkhe-wfc4q) is delta index compatible (mlv=19)
[MRIW7] 2024/02/03 12:52:22.076682 set.go:385: DEBUG: afkhe-wfc4q IndexID(I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU)
[MRIW7] 2024/02/03 12:52:22.077032 set.go:170: DEBUG: afkhe-wfc4q Snapshot()
[MRIW7] 2024/02/03 12:52:22.077065 set.go:192: DEBUG: afkhe-wfc4q WithNeed(7777777-777777N-7777777-777777N-7777777-777777N-7777777-77777Q4)
[MRIW7] 2024/02/03 12:52:22.077341 indexhandler.go:129: DEBUG: Starting index handler for afkhe-wfc4q to I6KAH76 at 127.0.0.1:22002-127.0.0.1:22001/tcp-server/TLS1.3-TLS_AES_128_GCM_SHA256/LAN-P10-5TGB0EIM3KPN063SGPH7PPEAH8 (slv=19)
[MRIW7] 2024/02/03 12:52:22.077417 set.go:170: DEBUG: afkhe-wfc4q Snapshot()
[MRIW7] 2024/02/03 12:52:22.077442 set.go:224: DEBUG: afkhe-wfc4q WithHaveSequence(20)
[MRIW7] 2024/02/03 12:52:22.077498 indexhandler.go:229: DEBUG: indexHandler@0x140001ea2a0 for afkhe-wfc4q to I6KAH76 at 127.0.0.1:22002-127.0.0.1:22001/tcp-server/TLS1.3-TLS_AES_128_GCM_SHA256/LAN-P10-5TGB0EIM3KPN063SGPH7PPEAH8: Sending 1 files (<341 bytes)

### prevSequence (in the IndexHandler) is the state of before the addition of a file locally

[MRIW7] 2024/02/03 12:52:22.077526 indexhandler.go:170: DEBUG: fset.Sequence: 27, s.prevSequence: 25
[MRIW7] 2024/02/03 12:52:32.133462 set.go:170: DEBUG: afkhe-wfc4q Snapshot()
[MRIW7] 2024/02/03 12:52:32.133509 set.go:224: DEBUG: afkhe-wfc4q WithHaveSequence(26)
[MRIW7] 2024/02/03 12:52:22.328716 indexhandler.go:170: DEBUG: fset.Sequence: 27, s.prevSequence: 25
[MRIW7] 2024/02/03 12:52:32.133462 set.go:170: DEBUG: afkhe-wfc4q Snapshot()
[MRIW7] 2024/02/03 12:52:32.133509 set.go:224: DEBUG: afkhe-wfc4q WithHaveSequence(26)
[MRIW7] 2024/02/03 12:52:22.580022 indexhandler.go:170: DEBUG: fset.Sequence: 27, s.prevSequence: 25
[MRIW7] 2024/02/03 12:52:32.133462 set.go:170: DEBUG: afkhe-wfc4q Snapshot()
[MRIW7] 2024/02/03 12:52:32.133509 set.go:224: DEBUG: afkhe-wfc4q WithHaveSequence(26)
[MRIW7] 2024/02/03 12:52:22.831431 indexhandler.go:170: DEBUG: fset.Sequence: 27, s.prevSequence: 25
[MRIW7] 2024/02/03 12:52:32.133462 set.go:170: DEBUG: afkhe-wfc4q Snapshot()
[MRIW7] 2024/02/03 12:52:32.133509 set.go:224: DEBUG: afkhe-wfc4q WithHaveSequence(26)
[MRIW7] 2024/02/03 12:52:23.082581 indexhandler.go:170: DEBUG: fset.Sequence: 27, s.prevSequence: 25
[MRIW7] 2024/02/03 12:52:32.133462 set.go:170: DEBUG: afkhe-wfc4q Snapshot()
[MRIW7] 2024/02/03 12:52:32.133509 set.go:224: DEBUG: afkhe-wfc4q WithHaveSequence(26)
[MRIW7] 2024/02/03 12:52:23.334155 indexhandler.go:170: DEBUG: fset.Sequence: 27, s.prevSequence: 25
[MRIW7] 2024/02/03 12:52:32.133462 set.go:170: DEBUG: afkhe-wfc4q Snapshot()
[MRIW7] 2024/02/03 12:52:32.133509 set.go:224: DEBUG: afkhe-wfc4q WithHaveSequence(26)
[MRIW7] 2024/02/03 12:52:23.585569 indexhandler.go:170: DEBUG: fset.Sequence: 27, s.prevSequence: 25
[MRIW7] 2024/02/03 12:52:32.133462 set.go:170: DEBUG: afkhe-wfc4q Snapshot()
[MRIW7] 2024/02/03 12:52:32.133509 set.go:224: DEBUG: afkhe-wfc4q WithHaveSequence(26)
[MRIW7] 2024/02/03 12:52:23.837042 indexhandler.go:170: DEBUG: fset.Sequence: 27, s.prevSequence: 25
[MRIW7] 2024/02/03 12:52:32.133462 set.go:170: DEBUG: afkhe-wfc4q Snapshot()
[MRIW7] 2024/02/03 12:52:32.133509 set.go:224: DEBUG: afkhe-wfc4q WithHaveSequence(26)
[MRIW7] 2024/02/03 12:52:24.088660 indexhandler.go:170: DEBUG: fset.Sequence: 27, s.prevSequence: 25
[MRIW7] 2024/02/03 12:52:32.133462 set.go:170: DEBUG: afkhe-wfc4q Snapshot()
[MRIW7] 2024/02/03 12:52:32.133509 set.go:224: DEBUG: afkhe-wfc4q WithHaveSequence(26)
[MRIW7] 2024/02/03 12:52:24.339713 indexhandler.go:170: DEBUG: fset.Sequence: 27, s.prevSequence: 25
[MRIW7] 2024/02/03 12:52:32.133462 set.go:170: DEBUG: afkhe-wfc4q Snapshot()
[MRIW7] 2024/02/03 12:52:32.133509 set.go:224: DEBUG: afkhe-wfc4q WithHaveSequence(26)
[MRIW7] 2024/02/03 12:52:24.590524 indexhandler.go:170: DEBUG: fset.Sequence: 27, s.prevSequence: 25
[MRIW7] 2024/02/03 12:52:32.133462 set.go:170: DEBUG: afkhe-wfc4q Snapshot()
[MRIW7] 2024/02/03 12:52:32.133509 set.go:224: DEBUG: afkhe-wfc4q WithHaveSequence(26)
[MRIW7] 2024/02/03 12:52:24.841872 indexhandler.go:170: DEBUG: fset.Sequence: 27, s.prevSequence: 25
[MRIW7] 2024/02/03 12:52:32.133462 set.go:170: DEBUG: afkhe-wfc4q Snapshot()
[MRIW7] 2024/02/03 12:52:32.133509 set.go:224: DEBUG: afkhe-wfc4q WithHaveSequence(26)
[MRIW7] 2024/02/03 12:52:25.093186 indexhandler.go:170: DEBUG: fset.Sequence: 27, s.prevSequence: 25
[MRIW7] 2024/02/03 12:52:32.133462 set.go:170: DEBUG: afkhe-wfc4q Snapshot()
[MRIW7] 2024/02/03 12:52:32.133509 set.go:224: DEBUG: afkhe-wfc4q WithHaveSequence(26)
[MRIW7] 2024/02/03 12:52:25.344735 indexhandler.go:170: DEBUG: fset.Sequence: 27, s.prevSequence: 25
[MRIW7] 2024/02/03 12:52:32.133462 set.go:170: DEBUG: afkhe-wfc4q Snapshot()
[MRIW7] 2024/02/03 12:52:32.133509 set.go:224: DEBUG: afkhe-wfc4q WithHaveSequence(26)
[MRIW7] 2024/02/03 12:52:25.596336 indexhandler.go:170: DEBUG: fset.Sequence: 27, s.prevSequence: 25
[MRIW7] 2024/02/03 12:52:32.133462 set.go:170: DEBUG: afkhe-wfc4q Snapshot()
[MRIW7] 2024/02/03 12:52:32.133509 set.go:224: DEBUG: afkhe-wfc4q WithHaveSequence(26)
[MRIW7] 2024/02/03 12:52:25.847762 indexhandler.go:170: DEBUG: fset.Sequence: 27, s.prevSequence: 25
[MRIW7] 2024/02/03 12:52:32.133462 set.go:170: DEBUG: afkhe-wfc4q Snapshot()
[MRIW7] 2024/02/03 12:52:32.133509 set.go:224: DEBUG: afkhe-wfc4q WithHaveSequence(26)
[MRIW7] 2024/02/03 12:52:26.099432 indexhandler.go:170: DEBUG: fset.Sequence: 27, s.prevSequence: 25
[MRIW7] 2024/02/03 12:52:32.133462 set.go:170: DEBUG: afkhe-wfc4q Snapshot()
[MRIW7] 2024/02/03 12:52:32.133509 set.go:224: DEBUG: afkhe-wfc4q WithHaveSequence(26)
...
```


Discussion / hints:
`s.prevSequence` initially comes from the remote, i.e. what it sends in the cluster config. So the remote here is only aware of the local file infos up to sequence 25.

Looking at `indexHandler.sendIndexTo` and the lack of any logging, that suggests file infos with sequence >25 are marked as receive-only-changed (L281) or don't exist at all. Sequence numbers being low/out-of-order is checked with debug logging enabled, that would result in a panic.

And indeed on revert we keep that flag when reverting, to avoid sending the index update, see folder_recvenc.go L83+.

Now comes the part that explains this observation of yours (emphasis mine):

> 2. On the receiving end, create a file or folder. *Editing a properly synced encrypted file does not seem to trigger this (and overall works as expected)*

The revert triggers a scan, and for a real file that exists on a remote, nothing happens on scan. As the revert reset the version, it gets pulled in and everything is up-to-date again.

For a locally created file there is no global equivalent. This triggers a special case that removes the file info from the DB (folder.go L607+), and that's where the sequence gets messed up. Stepping back to the beginning:
   
1. After creating the file it is scanned and added to the db -> sequence 26
Nothing sent to the remote, as it's locally changed in an encrypted folder.
2. Then it gets removed in the revert -> sequence 27
Not sent, as above.
3. Scan sees that we have a locally changed, deleted entry without any file info from remotes -> removes it from the DB.  
Now the last used sequence is still 27, however the highest sequence of any file in the DB is 25 -> index sender loops forever doing nothing.

I think the right solution here is in indexhandler.sendIndexTo, if there was nothing to send, set s.prevSequence to fset.Sequence. Any new change will get a higher sequence, so we can't miss anything - there's no point looking at anything `< fset.Sequence` anymore.  
Edit: Actually finding something to check in the test might be nasty, as there's no incorrect external behaviour, just a loop doing nothing. Not sure how to detect that.

That's easy to do, writing a test-case is likely going to be a bit of work. Hopefully some testcase from `folder_recvonly_test.go` is easily adaptable.

@er-pa I won't work on this right now, but will at some point unless you pick it up (very welcome to, you anyway already did the hard work of tracking it down - thanks a lot again!). As in please leave a note here if you do start to work on it.

Fix patch:
diff --git a/lib/model/indexhandler.go b/lib/model/indexhandler.go
index 30b56c69561..efa2754a93a 100644
--- a/lib/model/indexhandler.go
+++ b/lib/model/indexhandler.go
@@ -295,12 +295,13 @@ func (s *indexHandler) sendIndexTo(ctx context.Context, fset *db.FileSet) error
 
 	err = batch.Flush()
 
-	// True if there was nothing to be sent
-	if f.Sequence == 0 {
-		return err
-	}
+	// Use the sequence of the snapshot we iterated as a starting point for the
+	// next run. Previously we used the sequence of the last file we sent,
+	// however it's possible that a higher sequence exists, just doesn't need to
+	// be sent (e.g. in a receive-only folder, when a local change was
+	// reverted). No point trying to send nothing again.
+	s.prevSequence = snap.Sequence(protocol.LocalDeviceID)
 
-	s.prevSequence = f.Sequence
 	return err
 }
 


Test patch: