resident: flush silently overwrites external writes to the same file (lost update, no warning)
Version: 1.0.148 (macOS arm64)
Summary
While a resident holds a document, any change another program makes to that file on disk is silently discarded by the resident's next flush (save / close / idle auto-flush). No warning, no error, no non-zero exit — the external write just disappears.
The docs cover the read side of this well (save: "a direct disk reader sees the pre-edit file until a flush") and create already refuses a resident-held file with file_locked. The write side has no equivalent protection.
Repro
officecli create b.docx
officecli close b.docx
officecli open b.docx
officecli add b.docx /body --type p --prop text="FROM_OFFICECLI"
# an external program edits the same file on disk while the resident is live
python3 - <<'PY'
import zipfile, shutil
zin = zipfile.ZipFile('b.docx'); zout = zipfile.ZipFile('b.tmp', 'w', zipfile.ZIP_DEFLATED)
for it in zin.infolist():
d = zin.read(it.filename)
if it.filename == 'word/document.xml':
d = d.decode().replace('</w:body>', '<w:p><w:r><w:t>FROM_EXTERNAL</w:t></w:r></w:p></w:body>').encode()
zout.writestr(it, d)
zout.close(); zin.close(); shutil.move('b.tmp', 'b.docx')
PY
python3 -c "import zipfile;x=zipfile.ZipFile('b.docx').read('word/document.xml').decode();print('before flush -> external:',x.count('FROM_EXTERNAL'))"
officecli close b.docx
python3 -c "import zipfile;x=zipfile.ZipFile('b.docx').read('word/document.xml').decode();print('after flush -> officecli:',x.count('FROM_OFFICECLI'),' external:',x.count('FROM_EXTERNAL'))"Actual
before flush -> external: 1
after flush -> officecli: 1 external: 0Expected
The flush should notice the file changed underneath it and refuse, rather than overwrite.
Why this one hurts
An agent that repairs a document with its own script (dedup, search/replace, XML surgery) verifies the result on disk, sees it is correct, and reports success — then the resident flushes and the repair is gone. There is no signal it could have checked.
Combined with the raw-set rollback issue this cost us a user's document: the dedup script ran correctly, and the flush put the duplicated section straight back.
Suggested fix
Capture mtime/size/hash at open, and on flush refuse with a clear error when the file changed underneath — the same protective instinct create already has with file_locked. A --force style opt-out would cover the cases where clobbering is intended.
Source: iOfficeAI/OfficeCLI