iOfficeAI / iOfficeAI/OfficeCLI
[BUG] docx: resident's unflushed in-memory edits silently lost if resident dies before idle auto-flush; next process reports "No pending changes"
- Dominant language
- C#
- Stars
- 30.7k
- Forks
- 2.1k
- Avg merge
- 9d 8h
- Merged PRs (30d)
- 5
Description
## 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)
```bash
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
1. Crash-safe durability for resident dirty state (WAL or flush-before-ack for mutating commands; keep deferred flush for reads).
2. Honest recovery messaging: distinguish "nothing was ever pending" from "a previous resident terminated abnormally".
3. 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).
Contributor guide
Research direction
Reproduce the loss with the documented officecli create, open, set, resident termination, and save sequence, then compare it with OFFICECLI_RESIDENT_FLUSH=each. Trace the resident lifecycle and recovery path, including mutation acknowledgement and the save/close status; done means an acknowledged edit survives abnormal termination or the next process reports the unflushed loss instead of "No pending changes."
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- backend, cli
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100