Generated text needs an undo history
V0M3 made accepted model changes ordinary document revisions, preserving exact operations and lineage so removal, restoration, and explanation remained possible later.
I accepted a generated paragraph, edited two sentences, moved it beneath another section, and decided a week later that its premise was wrong.
The editor's Undo command could not help. Its in-memory stack had disappeared with the original tab. Restoring an old snapshot would erase unrelated work. Copying the earlier document into a new revision would recover the paragraph's absence but hide which later changes had been intentionally preserved.
The problem was not specific to generated text. It was a document-history problem made sharper by generation. V0M3 knew exactly which operations a proposal introduced and why. Throwing that structure away at acceptance produced less accountability precisely when the writing gained authority.
Generated text needed an undo history that survived the editor session.
Acceptance became a revision, not a paste
Early V0M3 inserted accepted prose into the current editor buffer and saved the result. The document service recorded a new snapshot, but the acceptance event and proposal operations were connected mostly through timestamps.
That was enough to display the latest document and too little to explain it.
I changed acceptance to a document command. It named the base revision, proposal revision, selected operation identities, normalized patch digest, author, approval receipt, and request identity. A successful command produced a new immutable document revision and a receipt linking every applied operation to the resulting spans.
The text remained ordinary text. The revision remembered how it arrived.
Browser undo and historical undo solved different problems
The editor still needed immediate Undo and Redo for typing, deletion, and local rearrangement. Those commands were fast, familiar, and scoped to an active editing session.
Historical undo answered a different question: how should a committed change from an earlier revision be removed without discarding everything after it?
V0M3 called the second operation Revert. A revert proposed an inverse patch against the current revision, showed conflicts and consequences, then created another forward revision when accepted. History never moved backward or lost a commit.
Using distinct names prevented a durable operation from masquerading as a harmless keystroke.
An operation-only history made reconstruction elegant until a migration bug or long chain made reads fragile. Snapshot-only history made reads simple but explanation and selective revert difficult.
V0M3 kept immutable revisions with canonical snapshots and the operation batch that produced each one. Snapshots allowed reliable reads, exports, and integrity checks. Operations allowed review, provenance, inversion, and analysis.
Each revision included:
- Its parent revision and canonical document digest.
- The command and idempotency identity that created it.
- Insert, replace, delete, move, and annotation operations.
- Proposal and evidence lineage where applicable.
- Author-written edits represented as authored operations.
- The renderer and normalization versions used.
Periodic verification replayed bounded chains and compared the computed digest with the stored snapshot. A mismatch stopped migration rather than quietly rewriting history.
Inversion was prepared at commit time
Some operations are easy to invert only while their original context is present. An insertion can be deleted, but a deletion needs the removed content. A replacement needs both old and new spans. A move needs the source and destination anchors before later edits blur them.
At commit time, V0M3 recorded sufficient inverse material beside the operation: removed content digest and encrypted payload where retention allowed, structural anchors, neighboring node identities, and the exact resulting range.
This did not make every future revert automatic. It made a faithful inverse proposal possible.
Sensitive removed text followed document retention policy. If the payload had expired, V0M3 could explain the historical deletion but could not promise restoration. Auditability and indefinite content retention were separate decisions.
Stable nodes survived ordinary editing
Character offsets were unreliable after paragraphs moved or preceding text changed. V0M3 assigned stable identities to structural nodes such as headings, paragraphs, list items, and code blocks.
Operations targeted node identity plus a content precondition. Inline ranges used local anchors and surrounding digests. When an author split or merged a node, the revision recorded lineage from old identities to new ones where it could do so unambiguously.
This let a later revert find the descendant of an accepted paragraph after it moved. It did not assume the paragraph was unchanged.
If lineage forked or the content had been substantially rewritten, the revert became a conflict requiring review.
Generated origin did not own later human edits
Suppose a proposal inserted a paragraph and the author later replaced half of it. “Remove generated text” must not blindly delete the author's contribution.
V0M3 tracked span lineage through revisions, but it did not claim perfect authorship at the character level. Direct descendants of the accepted operation were identifiable. Later replacements were new authored operations connected to, not owned by, the original proposal.
The revert preview divided the current descendant into unchanged generated material, human-modified material, structurally entangled material, and content already absent. Automatic removal applied only where preconditions remained clear.
The author decided what to do with the rest.
This was less magical than a colored AI-text overlay and far more respectful.
Selective revert preserved unrelated work
A proposal could contain five operations. The author might later regret one factual paragraph while keeping a useful table and two headings.
Revert began from operation identities, not the entire proposal snapshot. It generated inverse candidates for the selected operations against the current document. Unrelated revisions remained in place.
Dependencies were visible. Removing a definition could leave a later reference unresolved. Restoring a deleted section could duplicate a new replacement. A move might no longer have a meaningful former location.
Validation checked structure, references, evidence links, and document rules before the inverse patch could be accepted. Selectivity did not excuse inconsistency.
Rejection also belonged in history
Rejected proposals never entered the canonical document, so they did not need a document revert. They still mattered to the work's lineage.
V0M3 retained proposal state, review notes, selected evidence, and a rejection reason such as inaccurate, wrong voice, redundant, out of scope, or superseded. The reason could be private and concise. It was not used to manufacture a performance score.
When a later task resembled a rejected one, the interface could show the earlier decision without automatically feeding sensitive notes to a provider. The author could reconsider or deliberately avoid repeating the same alternative.
History included paths not taken because authorship includes refusal.
After reverting generated text, an author might decide the original was better. V0M3 did not toggle a hidden active flag. It prepared a Restore proposal from the inverse revision's evidence.
The current document could have changed again, so restore performed the same target, conflict, evidence, and structural checks as any other patch. A restoration created a new forward revision with links to the original acceptance and intervening revert.
This produced a longer history than moving a pointer. It also told the truth: the document had changed, the decision had changed, and the new state was reviewed under current conditions.
Revert was not compensation for external effects
Most V0M3 changes affected a document. Exporting or publishing a revision crossed into another system. Reverting the source document could not retract a downloaded file, invalidate a copied passage, or guarantee that a destination removed an earlier version.
The interface showed external receipts connected to the revision being reverted. Where a destination supported a separate replacement or withdrawal capability, that became its own proposed action with current authority and recovery limits.
I avoided the word Undo for those effects. A compensating action can fail, race, or leave traces. The document history could explain the desired correction without pretending the world reversed.
This lesson came directly from Z29C's durable workflows.
Evidence lineage survived removal
When an accepted claim was later deleted, its source relationship remained part of history. V0M3 marked the active document span absent while retaining the source revision, claim assessment, proposal operation, acceptance, later edits, and removal revision.
That mattered in two directions. A reviewer could understand why a statement once appeared. A later writer could see that it had been removed and avoid presenting the old citation as current support.
The evidence graph described time. It was not merely an index of citations visible in the latest document.
If a source itself was deleted under policy, the graph retained a tombstone and safe metadata rather than preserving prohibited content through provenance.
History needed a readable interface
A raw event log made the system complete and unusable. I organized history around document revisions and meaningful commands.
Each entry answered:
- What changed?
- Who or what proposed it?
- Who accepted or authored it?
- Which document revision did it target?
- What evidence and validation were available?
- What happened afterward?
- Can any part be safely reverted now?
The default summary used headings, operation counts, and short diffs. Technical identifiers, full operation payloads, and receipts remained available for investigation.
Generated changes were labelled in their proposal and acceptance lineage, not painted permanently across the reading surface.
Line-oriented diffs were useful for Markdown storage and poor at explaining a moved paragraph or a changed claim. V0M3 offered three coordinated views.
The structural view showed inserted, removed, moved, and changed nodes. The textual view showed precise content differences. The claim view showed evidence status changes such as supported to unsupported or narrowed to broadened.
A revert preview used the same views. The author could see that a short inverse patch removed a negation, broke a link target, or revived a claim whose source had changed.
No one representation was made authoritative for every review question. The underlying normalized operations connected them.
Branches remained explicit
V0M3 was primarily a linear authored document, but offline work or deliberate alternatives could produce branches. I refused to hide this behind last-write-wins.
Each branch kept its base revision. Merging prepared a new operation batch against the chosen current branch and surfaced conflicts. Reverting a change on one branch did not mutate another branch's history.
Proposal lineage also remained branch-specific. An acceptance reviewed against one document lineage could not be replayed onto another merely because some text matched.
This was heavier than a typical note editor and reserved for documents that needed it. The same model scaled down to a simple parent revision when no branch existed.
An undo promise implies retained material. Keeping every deleted draft forever would conflict with privacy, storage, and author expectations.
V0M3 let a workspace define revision retention, protected milestones, and sensitive-content rules. Before an old payload expired, the interface explained which historical revisions would remain describable but no longer restorable in full.
Export could include the current document, selected revision history, and a provenance sidecar according to policy. Deleting the workspace followed a separate verified workflow that included history, proposal artifacts, indexes, and encrypted payloads.
“Unlimited history” was not a feature label I could justify.
Compaction preserved decisions
Long histories needed compaction for efficient reads. Compaction created verified snapshots and indexes; it did not collapse accept, edit, reject, revert, or restore into an unexplained final blob.
The semantic event chain and digests remained. Large intermediate render artifacts and replaceable indexes could expire. Content needed for a promised revert followed its retention class.
A compacted revision could still answer why a paragraph existed, which proposal introduced it, and which later command removed it. Performance work did not erase authorship evidence.
The distinction kept a raw interaction history from masquerading as the durable state needed to continue the work.
Undo exposed architectural mistakes
The feature repeatedly found places where I had coupled state to a view. Some acceptance metadata lived only in the review page. Some node identities changed during rendering. Some evidence links pointed to display offsets rather than canonical spans.
Making old changes safely invertible forced those concepts into the document domain. Review became a durable record. Rendering became a projection. Node lineage became explicit. External effects acquired separate receipts.
Undo was not a decorative editor feature. It was a test of whether the system actually knew what a change meant.
An author could open a revert preview while another tab committed a manual edit. Applying the inverse against the revision originally inspected would either lose the newer change or make the receipt dishonest.
The revert command bound its exact current revision. If that revision changed, V0M3 did not auto-apply. It rebased the inverse candidates onto the new head, reran structural and claim validation, and produced a new review digest. Cleanly relocated operations still required renewed acceptance because the object had changed.
Conflicts preserved both intentions: remove the historical operation and keep the later authored edit. The interface showed the smallest overlapping node and offered explicit resolution choices. It never called a last-write-wins result an undo.
Idempotency covered repeated submission of one accepted revert command. It did not authorize the same semantic request against a different document revision.
Milestones made long history navigable
A list of hundreds of revisions answered every audit question badly. V0M3 let the author mark named milestones such as outline agreed, evidence review complete, and first external draft.
A milestone was a label on an immutable revision, not a copied document or movable pointer. Comparing current work with a milestone produced structural, textual, and claim-level differences. Preparing a return to that state still created a forward patch and preserved intervening work for review.
Automatic checkpoints could help recovery but stayed visually secondary. Milestones represented authored meaning. They made history useful without pretending every save was equally important.
Recovery was tested outside the happy editor
I tested history by closing the tab after acceptance, opening the document on another device, losing the local editor cache, and restoring the database into a fresh environment. The same revision, receipt, and revert preview had to appear.
Backup verification checked content digests and referenced operation payloads, not only whether rows could be restored. A revision whose snapshot existed but whose promised inverse material was missing was reported as degraded history.
Keyboard and screen-reader flows received the same care. Revision entries used real headings and lists; additions and deletions had textual labels; focus returned to the changed section after a preview closed. A color-only provenance timeline would have made accountability available only to some authors.
Durability included the ability to understand the recovered state.
The limit was semantic intention
V0M3 could preserve operations, lineage, evidence, and exact bytes. It could not infer every intention behind later human editing.
A paragraph might inspire a completely rewritten section. A removed sentence might still influence the argument. Two independent edits might converge on the same wording. Character provenance could suggest a story and still miss the intellectual one.
The interface used cautious language: introduced by, modified after, derived from, no longer present. It allowed notes and explicit decisions where exact mechanics stopped explaining authorship.
The goal was accountable history, not a false measurement of originality.
A document could change its mind without losing itself
Once acceptance created a durable revision, generated text stopped being a special paste. It became part of the document's history under the same rules as other consequential changes.
That did not make every change permanent. It made reversal precise.
The author could remove one operation without erasing a week of work, retain later human edits where ownership had diverged, restore an older decision under current preconditions, and follow evidence through acceptance and removal. External consequences remained separate and honest.
The larger lesson was about memory. A trustworthy writing tool should remember enough to support changed judgment without making old judgment secretly disappear.
Generated text needs that history because it arrives quickly and often sounds finished. Authorship takes longer. It includes the right to inspect, alter, refuse, and eventually say: this was useful once, but it no longer belongs here.
That right remained meaningful only because the document could change direction without concealing the decisions, evidence, and revisions that brought it there.