A FLEx user's deletion of a settings file cannot stick. FwHeadless re-commits the file on its next sync, indefinitely.
Measured on one production project, where the same reversal-index configuration under CachedSettings/ConfigurationSettings/ReversalIndex/ went through three full cycles:
| when |
who |
what |
| Nov 2023 |
FLEx user |
created |
| Jun 2025 |
FLEx user |
deleted |
| Mar 2026 |
FwHeadless |
re-added |
| Mar 2026, four days later |
FLEx user |
deleted again |
| Jul 2026 |
FwHeadless |
re-added |
| Jul 2026, three weeks later |
FLEx user |
deleted again |
| Jul 2026, a week after that |
FwHeadless |
kept by its merge; present at the repo tip today |
It is only UI configuration, so nothing was lost. But the loop is mechanical, it has run three times, and it will keep running.
Mechanism
FwHeadless's project directory is long-lived: it is the fwdata cache, and it survives between syncs. hg update never removes untracked files, so a copy of the file has been sitting in the working directory's ConfigurationSettings/ since it was first created, and no checkout will ever clear it.
FLExBridge then copies the settings folders into the tracked CachedSettings/ tree on every send/receive, and CachedSettings/ tracks files that ConfigurationSettings/ does not: several ReversalIndex/*.fwdictconfig files exist only under CachedSettings/ in that project's repository. So the stray gets committed through the cache each time, no matter how many times a user deletes it.
Same class of problem, not observed leaking yet: two WritingSystemStore/*.ldml files are also untracked in that directory. If those ever reach the cache, the container starts inventing writing systems for the project.
Why "purge untracked files" is the wrong fix
The untracked set in a real project directory:
fw.fwdata the project itself, reconstituted at checkout
fw.bak its backup
ConfigurationSettings/** 17 files, the actual leak
WritingSystemStore/*.ldml 2 files
SharedSettings/LexiconSettings.plsx
hg purge, or hg update -C with --clean semantics over the whole tree, deletes the project. Any fix has to name what it removes rather than removing what it does not recognise.
What needs deciding
A rule for which subtrees are project data, never touched, and which are container-local state that may be reconciled. Proposal to argue with:
- Reconcile
ConfigurationSettings/ only. It is regenerable UI configuration and never holds lexical data.
- Delete a file there only when the tracked
CachedSettings/ConfigurationSettings/ tree at the current revision does not contain it. That borrows FLExBridge's own idea of what belongs to the project instead of inventing a list we have to maintain.
- Do not touch the project root,
LinkedFiles/, WritingSystemStore/ or SharedSettings/ in this pass. Flag the writing-system strays separately.
- Run it after checkout and before the pre-sync send/receive, so a stray never reaches the cache in the first place.
Tests
- a stray file dropped into
ConfigurationSettings/ is absent from the commit the sync produces
fw.fwdata, fw.bak, LinkedFiles/** and untracked WritingSystemStore/*.ldml all survive the reconcile
- a settings file that is tracked under
CachedSettings/ is not deleted
- regression: a file deleted upstream and still present untracked locally does not reappear in the next commit
Notes
Found while auditing what the sync has written into fwdata across a project's full Mercurial history. It is the only thing the sync has re-added to a repository more than once, which is what makes it worth its own issue rather than a footnote.
A FLEx user's deletion of a settings file cannot stick. FwHeadless re-commits the file on its next sync, indefinitely.
Measured on one production project, where the same reversal-index configuration under
CachedSettings/ConfigurationSettings/ReversalIndex/went through three full cycles:It is only UI configuration, so nothing was lost. But the loop is mechanical, it has run three times, and it will keep running.
Mechanism
FwHeadless's project directory is long-lived: it is the fwdata cache, and it survives between syncs.
hg updatenever removes untracked files, so a copy of the file has been sitting in the working directory'sConfigurationSettings/since it was first created, and no checkout will ever clear it.FLExBridge then copies the settings folders into the tracked
CachedSettings/tree on every send/receive, andCachedSettings/tracks files thatConfigurationSettings/does not: severalReversalIndex/*.fwdictconfigfiles exist only underCachedSettings/in that project's repository. So the stray gets committed through the cache each time, no matter how many times a user deletes it.Same class of problem, not observed leaking yet: two
WritingSystemStore/*.ldmlfiles are also untracked in that directory. If those ever reach the cache, the container starts inventing writing systems for the project.Why "purge untracked files" is the wrong fix
The untracked set in a real project directory:
hg purge, orhg update -Cwith--cleansemantics over the whole tree, deletes the project. Any fix has to name what it removes rather than removing what it does not recognise.What needs deciding
A rule for which subtrees are project data, never touched, and which are container-local state that may be reconciled. Proposal to argue with:
ConfigurationSettings/only. It is regenerable UI configuration and never holds lexical data.CachedSettings/ConfigurationSettings/tree at the current revision does not contain it. That borrows FLExBridge's own idea of what belongs to the project instead of inventing a list we have to maintain.LinkedFiles/,WritingSystemStore/orSharedSettings/in this pass. Flag the writing-system strays separately.Tests
ConfigurationSettings/is absent from the commit the sync producesfw.fwdata,fw.bak,LinkedFiles/**and untrackedWritingSystemStore/*.ldmlall survive the reconcileCachedSettings/is not deletedNotes
Found while auditing what the sync has written into fwdata across a project's full Mercurial history. It is the only thing the sync has re-added to a repository more than once, which is what makes it worth its own issue rather than a footnote.