set --body-file destroys the body irreversibly; no history, no empty-guard - #111
Merged
Conversation
`voro set --body-file` swapped a task's whole brief for whatever the file held, in place, with nothing left behind — the one field an edit destroys outright and the one whose loss cannot be reconstructed from state elsewhere. Working mote #286 an agent ran `set 284 --body-file /dev/null` meaning a no-op and wiped #284's body; the events table stores only kind/detail transitions, so the text was unrecoverable and had to be rewritten by hand from the parent task's context. Every edit that changes a non-empty body now records the text it replaced as a `body` event on the append-only log. It rides `Store::update_task`, so it covers all three writers — the CLI flag, a refine agent, and the TUI editor — and only fires on a real change, since every `set` passes through there. That detail is bulk kept for recovery rather than reading, so `show` and the TUI history fold it to a marker naming the event that holds it (`replaced body kept (37 lines) — voro show 62 --event 512`) instead of unrolling a superseded brief into the log, and `voro show <id> --event <event-id>` prints one event's detail alone and undecorated, so recovery is a redirect back through `set --body-file` rather than a verb of its own. A replacement that would leave a non-empty body empty is refused unless `--allow-empty` says so: nothing legitimate reads as "blank the brief", and the way one actually arrives is a slip. Emptying an already-empty body destroys nothing and passes unremarked. Beside the replacing pair sits an additive one, `--append-body`/`--append-body-file`, which adds after a blank line — the "record a finding on the task" case that was what the agent in the incident was actually trying to do. DESIGN.md §8 gains the paragraph, beside the summary's, and the skill's CLI reference names both new flags.
MJohnson459
force-pushed
the
body-history-guard
branch
from
August 1, 2026 19:57
b0f6ed0 to
d838df1
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
voro set --body-fileswapped a task's whole brief for whatever the file held,in place, with nothing left behind — the one field an edit destroys outright and
the one whose loss cannot be reconstructed from state elsewhere. The 2026-07-29
incident (
set 284 --body-file /dev/null, meant as a no-op) was unrecoverablebecause the events table stores only kind/detail transitions.
Three changes, all three of the suggestions in the task body:
replaced as a
bodyevent on the append-only log. It ridesStore::update_task, so it covers all three writers — the CLI flag, a refineagent, and the TUI editor — and fires only on a real change, since every
setpasses through there. A body event's detail is bulk kept for recovery rather
than reading, so
showand the TUI history fold it to a marker naming theevent that holds it (
replaced body kept (37 lines) — voro show 62 --event 512) instead of unrolling a superseded brief into the log.voro show <id> --event <event-id>prints one event's detailalone and undecorated, so getting a body back is a redirect straight into
set --body-filerather than a verb of its own. The event must belong to thetask named.
unless
--allow-emptysays so; emptying an already-empty body destroysnothing and passes unremarked.
--append-body/--append-body-fileadd to theexisting body after a blank line — what the agent in the incident was actually
trying to do — and conflict with the replacing pair at the parser.
DESIGN.md §8 gains the paragraph (beside the summary's, which it mirrors: a
summary is superseded, a body is overwritten), the §5 events comment now names
replaced bodies, and the plugin skill's CLI reference names the new flags.
Verified:
cargo test --workspace(270 + 1 + 274, up 5 new tests covering theguard, the recovery round-trip, the append semantics, the store's log-only-on-
change rule, and the TUI history fold),
cargo clippy --workspace --all-targets -D warningsclean,cargo fmt --all. Also driven end-to-end against a scratchdatabase:
set 1 --body-file /dev/nullis refused with the line count intact,an append lands after a blank line, and a replaced body is recovered with
voro show 1 --event 3 > f.md && voro set 1 --body-file f.mdbyte-for-byte.Branch
body-history-guardis committed locally and not pushed (no pushwithout approval).