<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Harry Song (ubiquition)</title>
    <description>The latest articles on DEV Community by Harry Song (ubiquition) (@harry_songubiquition_c).</description>
    <link>https://dev.to/harry_songubiquition_c</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4216287%2F94286afb-8428-403c-8a8a-5e3e2f1dde9a.jpg</url>
      <title>DEV Community: Harry Song (ubiquition)</title>
      <link>https://dev.to/harry_songubiquition_c</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/harry_songubiquition_c"/>
    <language>en</language>
    <item>
      <title>An AI rewrite can be stale before you click Apply</title>
      <dc:creator>Harry Song (ubiquition)</dc:creator>
      <pubDate>Fri, 30 Oct 2026 03:39:41 +0000</pubDate>
      <link>https://dev.to/harry_songubiquition_c/an-ai-rewrite-can-be-stale-before-you-click-apply-4k42</link>
      <guid>https://dev.to/harry_songubiquition_c/an-ai-rewrite-can-be-stale-before-you-click-apply-4k42</guid>
      <description>&lt;p&gt;A document editor can show a perfectly reasonable AI suggestion that is already wrong to apply.&lt;/p&gt;

&lt;p&gt;Imagine a paragraph in a shared creative brief:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The father leaves the room.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A writer asks an agent to rewrite it. While the suggestion is being prepared, a collaborator changes the brief:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The father stays and helps his daughter.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The agent returns a polished version of the first sentence. Someone clicks Apply. The problem is no longer the quality of the generated sentence. It is whether the proposal still refers to the document people are editing now.&lt;/p&gt;

&lt;p&gt;A shared editing system can merge updates without understanding that a pending rewrite expresses an outdated decision. That requires a separate check in the proposal workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the proposal separate from the edit
&lt;/h2&gt;

&lt;p&gt;The implementation examined here is in &lt;a href="https://github.com/orime-org/breatic/tree/a4d62fadf356a9a667d273336ff9f99c8de2f798" rel="noopener noreferrer"&gt;Breatic's public repository&lt;/a&gt;. Its document-edit tool returns a proposal card rather than immediately rewriting the shared document.&lt;/p&gt;

&lt;p&gt;A proposal carries the target Space, a block ID, the block's original plain text, the proposed content, and its own proposal ID. Comments, rewrites and inserts use the same proposal shape, with different requirements for their targets.&lt;/p&gt;

&lt;p&gt;The original text is important. An ID tells the application which block the model saw. It does not tell the application whether that block still says the same thing.&lt;/p&gt;

&lt;p&gt;For a rewrite, the relevant check is conceptually this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;findBlockById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentDocument&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;proposal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;blockId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;block&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;outcome&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;blockGone&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;plainText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;proposal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;original&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;outcome&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;changed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is an explanatory sketch, not a standalone API example. In the implementation, the check reads the editor's current ProseMirror document. It compares the block's plain text, not a full structural hash of every attribute and mark.&lt;/p&gt;

&lt;p&gt;If the collaborator has rewritten the paragraph, the proposal is refused instead of silently replacing the new wording. The user can ask for another proposal against the current text.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fabp6ezboelet72jjifqr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fabp6ezboelet72jjifqr.png" alt="A document rewrite presented for review before replacement" width="800" height="479"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A real example-project capture. The scene is illustrative; the rewrite has not been applied in this image.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Check again after asynchronous preparation
&lt;/h2&gt;

&lt;p&gt;Putting the check in the click handler is not enough if the handler then awaits work.&lt;/p&gt;

&lt;p&gt;The proposed Markdown has to become editor blocks. Preparing those blocks can also wait for media configuration. During that interval, another edit can arrive, the target can disappear, or the current editor can become read-only.&lt;/p&gt;

&lt;p&gt;The landing function therefore checks the current state twice: before preparation and again after it finishes, immediately before the synchronous block write. A simplified outline is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;initial&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inspectCurrentState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initial&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;initial&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;prepared&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;prepareNewContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;proposal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ready&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inspectCurrentState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ready&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;ready&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;writePreparedBlocks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prepared&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;inspectCurrentState&lt;/code&gt; stands for more than the text comparison. It checks whether the request is still available, whether this proposal has already landed, the current write admission, whether the editor is editable, and the current target.&lt;/p&gt;

&lt;p&gt;Notice what is absent from the second check: a target position saved before the &lt;code&gt;await&lt;/code&gt;. The implementation looks up the block again by ID. A collaborator may have moved it, including into a table cell, without changing its words. The new content must be normalized for its current location.&lt;/p&gt;

&lt;h2&gt;
  
  
  Applying once needs a durable trace
&lt;/h2&gt;

&lt;p&gt;A second click should not insert the same proposal again. A local &lt;code&gt;applied = true&lt;/code&gt; flag does not explain what happened after a reload.&lt;/p&gt;

&lt;p&gt;For inserted or rewritten content, the implementation derives root block IDs from the proposal ID and each output block's index. A later render can look for that trace in the shared document. Comments instead carry proposal metadata on their thread and must still have a range in the document to count as landed.&lt;/p&gt;

&lt;p&gt;The trace describes the document's current state. If the write is undone and its output disappears, the proposal no longer counts as landed. If it is redone, the trace is there again.&lt;/p&gt;

&lt;p&gt;The write is also bracketed as one undo step. Accepting a multi-block suggestion should not require a user to undo its fragments one by one, or undo text they typed just before accepting it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test the gap rather than the happy path
&lt;/h2&gt;

&lt;p&gt;The useful regression case deliberately pauses asynchronous preparation. While it is paused, the test changes the target, removes it, or makes the editor read-only. It then releases preparation and checks the result.&lt;/p&gt;

&lt;p&gt;The public test suite asserts that these cases return &lt;code&gt;changed&lt;/code&gt;, &lt;code&gt;blockGone&lt;/code&gt;, or &lt;code&gt;readOnly&lt;/code&gt;, leave the current document intact, and do not add an undo item. Other cases move the target into or out of a table cell during preparation, and verify that output is normalized for the new location.&lt;/p&gt;

&lt;p&gt;The tests also cover repeated application, undo and redo, and reading the resulting document through a second Yjs document. These are assertions present in the repository; this article does not report a new benchmark or a fresh run of the full suite.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this check does not solve
&lt;/h2&gt;

&lt;p&gt;The plain-text comparison is a deliberately narrow guard. It does not detect every formatting-only change or establish that the model's interpretation of the brief is correct. A final browser-side check is also not a distributed lock against every remote update that might arrive later.&lt;/p&gt;

&lt;p&gt;Its job is more specific: refuse a proposal when the current local document no longer contains the text it was proposed against, and avoid using state captured before an asynchronous pause.&lt;/p&gt;

&lt;p&gt;The practical place to review a collaborative AI editing feature is the moment between “the user accepted this suggestion” and “the shared document changed.” That interval has its own state, permissions and failure cases, even when the suggestion itself looks finished.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation references
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/orime-org/breatic/blob/a4d62fadf356a9a667d273336ff9f99c8de2f798/packages/shared/src/types/document-proposal.ts" rel="noopener noreferrer"&gt;Proposal schema and original-text contract&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/orime-org/breatic/blob/a4d62fadf356a9a667d273336ff9f99c8de2f798/packages/domain/src/agent/tools/propose-document-edit.ts" rel="noopener noreferrer"&gt;Proposal generation without immediate document writes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/orime-org/breatic/blob/a4d62fadf356a9a667d273336ff9f99c8de2f798/packages/web/src/spaces/document/document-proposal-landing.ts" rel="noopener noreferrer"&gt;Commit-time checks and undo boundary&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/orime-org/breatic/blob/a4d62fadf356a9a667d273336ff9f99c8de2f798/packages/web/src/spaces/document/__tests__/document-proposal-commit.test.ts" rel="noopener noreferrer"&gt;Regression tests for changes during preparation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Disclosure: This article was prepared with AI assistance, using the linked public implementation and tests as its technical sources.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>webdev</category>
      <category>ai</category>
      <category>testing</category>
    </item>
  </channel>
</rss>
