Summary
When a live resident holds a .docx and a mutation (e.g. a tracked-change edit via --prop revision.type=ins) is applied through it, the change exists only in the resident's memory until the idle auto-flush (adaptive 2–10s) fires. If the resident process dies inside that window (SIGKILL, host-harness child reaping, crash), the dirty state is silently lost: the next officecli command spawns a fresh resident from the stale on-disk file, query/get show the pre-edit content, and save/close report "No pending changes" — actively telling the caller everything was saved when the edit is gone.
Field context: hit in an AI-agent harness (MyAgents) that runs each tool call in a separate short-lived exec segment. An agent did a tracked-change replace (matched: 1, same-process get showed revision.type=ins with the expected author), then the next exec segment saw ins/del counts back at 0, file content reverted, and save/close claiming already-saved. In that environment the resident evidently did not survive between segments.
Environment
- officecli 1.0.143, macOS arm64 (Darwin 25.5.0)
- default resident behavior (auto-kept-open after
create / explicit open)
Minimal reproduction (confirmed)
officecli create test.docx # resident kept open
officecli add test.docx /body --type paragraph --prop text="hello world"
officecli close test.docx # clean baseline on disk
officecli open test.docx # live resident
officecli set test.docx "/body/p[1]/run[1]" \
--prop text="hello brave world" --prop revision.type=ins --prop revision.author=X
unzip -p test.docx word/document.xml | grep -c 'w:ins' # -> 0 (deferred, as designed)
kill -9 "$(pgrep -f '__resident-serve__' | head -1)" # simulate harness reaping / crash
sleep 1
unzip -p test.docx word/document.xml | grep -c 'w:ins' # -> 0 (edit lost)
officecli query test.docx "revision[@type=ins]" --json # -> matches: 0
officecli get test.docx "/body/p[1]" --json # -> "hello world" (reverted)
officecli save test.docx --json # -> "No pending changes" (misleading)
Control observations, same version:
- If
set itself starts the resident (no pre-existing one), the command flushes before returning — no loss window.
OFFICECLI_RESIDENT_FLUSH=each works as documented: disk shows w:ins immediately after the mutating command returns. This is the workaround we now use in agent contexts.
Expected
Either (a) an acknowledged mutation survives resident death — e.g. journal/WAL replayed on next open, or flush-before-ack; or at minimum (b) the next process can detect that a resident died with unflushed changes and say so, instead of save reporting "No pending changes" as if the edit had been persisted.
Suggestions
- Crash-safe durability for resident dirty state (WAL or flush-before-ack for mutating commands; keep deferred flush for reads).
- Honest recovery messaging: distinguish "nothing was ever pending" from "a previous resident terminated abnormally".
- Document a supported way to disable auto-resident entirely for harnesses with short-lived process trees (
OFFICECLI_NO_AUTO_RESIDENT does not exist in 1.0.143 — only OFFICECLI_RESIDENT_FLUSH is documented), or document OFFICECLI_RESIDENT_FLUSH=each as the recommended agent-mode setting.
Related in spirit but distinct: #244 (xlsx batch atomicity under IPC failure).
Summary
When a live resident holds a .docx and a mutation (e.g. a tracked-change edit via
--prop revision.type=ins) is applied through it, the change exists only in the resident's memory until the idle auto-flush (adaptive 2–10s) fires. If the resident process dies inside that window (SIGKILL, host-harness child reaping, crash), the dirty state is silently lost: the next officecli command spawns a fresh resident from the stale on-disk file,query/getshow the pre-edit content, andsave/closereport "No pending changes" — actively telling the caller everything was saved when the edit is gone.Field context: hit in an AI-agent harness (MyAgents) that runs each tool call in a separate short-lived exec segment. An agent did a tracked-change replace (
matched: 1, same-processgetshowedrevision.type=inswith the expected author), then the next exec segment saw ins/del counts back at 0, file content reverted, andsave/closeclaiming already-saved. In that environment the resident evidently did not survive between segments.Environment
create/ explicitopen)Minimal reproduction (confirmed)
Control observations, same version:
setitself starts the resident (no pre-existing one), the command flushes before returning — no loss window.OFFICECLI_RESIDENT_FLUSH=eachworks as documented: disk showsw:insimmediately after the mutating command returns. This is the workaround we now use in agent contexts.Expected
Either (a) an acknowledged mutation survives resident death — e.g. journal/WAL replayed on next open, or flush-before-ack; or at minimum (b) the next process can detect that a resident died with unflushed changes and say so, instead of
savereporting "No pending changes" as if the edit had been persisted.Suggestions
OFFICECLI_NO_AUTO_RESIDENTdoes not exist in 1.0.143 — onlyOFFICECLI_RESIDENT_FLUSHis documented), or documentOFFICECLI_RESIDENT_FLUSH=eachas the recommended agent-mode setting.Related in spirit but distinct: #244 (xlsx batch atomicity under IPC failure).