A Stable Lossless Syntax Tree for Real-Time Collaborative Programming
Abstract
Real-time collaborative programming tools synchronize source code as text, propagating keystrokes or text patches to other collaborators. This propagation of unstructured text often leads to syntactically invalid states, because edits take place by character position rather than by syntactic entity. Consequently, our key idea is to propagate syntactically valid changes only.
This paper contributes a structure-aware synchronization substrate based on two complementary representations and a propagation algorithm: (i) A Lossless Syntax Tree stores source code in structured form while preserving program trivia, like whitespace and comments. This is necessary because collaborators must be able to reconstruct byte-identical source text from propagated (structural) changes; (ii) A Stable Syntax Tree extends this representation with persistent node identifiers to enable robust structural diffing between successive versions; (iii) Our propagation algorithm derives deterministic structural edit scripts for the following operations: insert, delete, move, and update. The algorithm can be used across grammars, because a lightweight per-language specification guides the stable reuse of node identifiers.
The biggest achievement of our approach is to take unstructured text changes and extract structural edit operations that provide syntactically correct source code changes. We formalize our proposed representations, show how diffing extracts structural edits, and how these edit scripts are applied at the collaborator. Particularly complex is the resulting move of subtrees. Our approach minimizes within-parent move noise using a per-parent Longest Increasing Subsequence.
We evaluate our approach using two languages (Java and JavaScript), three file sizes (small/medium/large), and five edit scenarios. Across all scenarios we observe byte-identical collaboration, node identity stability, and deterministic edit scripts. We demonstrate that applying Longest Increasing Subsequence is necessary for canonical minimality under sibling moves. We furthermore demonstrate that tree diffing cost is structure-sensitive: per-node cost increases with sibling fanout rather than depth. 95th percentile (p95) of end-to-end latencies meet the second delay budget for small and medium files in both languages. Large Java is near 1 second (p95 seconds) while JavaScript exceeds the 2 seconds hard-cap (p95 seconds). Overall, our approach provides a deterministic, language-portable substrate for structure-aware real-time collaborative programming that separates structural propagation from unstructured keystrokes to preserve code correctness and developer intent.
Keywords and phrases:
real-time collaborative programming, tree-based operations, structure-aware propagation, synchronous collaboration systemsCopyright and License:
2012 ACM Subject Classification:
Software and its engineering Software maintenance tools ; Software and its engineering Collaboration in software developmentSupplementary Material:
Software (Source Code, Evaluation Data and Scripts): https://doi.org/10.6084/m9.figshare.31368775 [16]Editors:
Robbert Krebbers and Alexandra SilvaSeries and Publisher:
Leibniz International Proceedings in Informatics, Schloss Dagstuhl – Leibniz-Zentrum für Informatik
1 Introduction
What is Real-time Collaborative Programming (RCP) and why we need it?
Software development has outgrown the lone programmer coding in a garage myth. It is a tool-rich, inherently collaborative process [12, 5, 47]. Yet, certain tasks demand high interaction and routinely leave developers navigating their teammates through code like “scroll to line 276…now type L-O-G”. These scenarios are common and break the programming flow, moments where simply taking over the keyboard would be more efficient. Real-time collaborative programming (RCP) environments emerged to enable these highly synchronous interactions inside Integrated Development Environments (IDEs) [45]. While many needs of collaborative programming are well served by asynchronous tools like Git, they do not suffice when immediate, shared context is required [26]. Such cases include pair and mob programming [42], code walkthroughs and interviews, teaching and peer learning [43], live troubleshooting, and concurrent edits to a single, tightly coupled artifact [45]. RCP tools belong to the field of Computer-Supported Cooperative Work (CSCW). In CSCW terms, synchronous groupware is constituted as “the class of applications in which two or more people collaborate in what they perceive to be real time” [7]. In practice, latencies vary but the community commonly uses real-time to denote such synchronous or near-synchronous systems. We follow this convention and use real-time collaborative programming to refer to these environments, treating real-time and synchronous interchangeably.
Why current tools do not suffice?
Popular RCP tools (e.g. JetBrains Code With Me [21], VS Code Live Share [28] and Replit [35]) synchronize and propagate changes at the text level via variants of Operational Transformation (OT) [41] or Conflict-free Replicated Data Types (CRDT) [25, 49, 50, 46]. However, mainstream OT and CRDT approaches target general-purpose text editing and are oblivious to programming language structure and semantic validity, so they routinely propagate syntactically invalid intermediate states that disrupt builds, analysis, and execution [30, 22, 40, 17, 33]. The result is chattiness (every keystroke broadcast) and visible lag on real networks [52, 45, 17], as well as weak synchronization semantics when multiple developers work on related code [14, 46, 33]. Host–participant architectures further constrain tooling and resilience [13]. Prior work [17] quantified these propagation inefficiencies and demonstrated that using a structure-aware model gating updates on syntactic validity can substantially reduce message volume and build-breaking states. Furthermore, it has been shown, that using a structure-aware model as a base for code synchronization enables better semantic-aware convergence that mirrors developer intent [30, 33].
Claim.
Real-time collaborative programming should elevate synchronization from text to program structure: edits should align to syntactic units, and change should be represented deterministically so it can be replayed across collaborators.
Concrete requirements for structure-aware RCP.
A core requirement in RCP is convergence to the same user-intended program state [25, 41, 46, 49, 33]. For code, this entails two practical constraints: (i) edits must preserve byte-level round trips, including trivia such as whitespace, line breaks, and comments; and (ii) propagation should be gated to parser-accepted states to avoid broadcasting transient syntax errors. In addition, HCI findings constrain interaction latency: local feedback should remain immediate (roughly – s) [29], while remote convergence need not be instantaneous but should typically complete within – s to feel seamless [32].
Modern IDE and compiler infrastructures already maintain incremental parse trees, providing keystroke-speed for single-user code analysis and completion. However, they were not designed as replication substrates: they are typically lossy with respect to source bytes and stable node identities across revisions are not available. Prior structure-aware RCP efforts [30, 33] assume simple languages where the Abstract Syntax Tree (AST) mirrors the source text, limiting applicability to mainstream languages and leaving code-to-structure-to-code round-tripping unsolved.
Research gaps.
Moving to structure is necessary but not sufficient. We found that three building blocks are missing in today’s tooling and research:
-
1.
Lossless, identity-stable syntax substrate with principled ID reuse. There is no substrate that simultaneously (i) guarantees byte-identical round trips, (ii) exposes persistent node identities across (re)parses, and (iii) specifies when existing IDs may be reused after edits (a reconciliation policy).
- 2.
-
3.
End-to-end pipeline: An incremental pipeline that localizes edits, preserves IDs, gates propagation to parser-accepted states, and prints byte-identically has not been demonstrated for Real-time Collaborative Programming.
Research questions.
Guided by the presented research gaps, we ask:
- RQ1.
- RQ2.
- RQ3.
-
Can a structure-aware approach meet established HCI response-time budgets, and how do program/tree-structure properties (e.g. node count, maximum sibling fanout, depth) influence those latencies across languages and edit scenarios? (evaluated in Section 6.)
Contributions.
Building on prior evidence of propagation inefficiency and non-parsable states in text-based RCP [17, 45, 52], and to answer the presented research questions, this paper makes the following contributions:
-
1.
A Lossless Syntax Tree (LST) and Stable Syntax Tree (SST) substrate with reconciliation. We combine a Lossless Syntax Tree that guarantees byte-identical round trips with a Stable Syntax Tree overlay that assigns persistent, parent-scoped identifiers. We specify and validate reconciliation rules that deterministically reuse IDs of nodes, yielding durable, unambiguous identities across revisions. (RQ1, RQ3)
-
2.
A deterministic structural edit algebra. We define and formalize a small, prescriptive operation set and a deterministic extraction (diffing) procedure that yield canonical, replayable edit scripts over stable identities and preserve lossless printing. (RQ2, RQ3)
-
3.
Proof-of-concept and evaluation. We implement the approach in a web-based code editor and extensively evaluate two languages (Java, JavaScript), multiple file sizes, and five edit scenarios, reporting determinism, identity stability, byte-identical replay, and end-to-end latency. (RQ1–RQ3)
Scope.
We do not address semantic concurrency control (e.g. intent inference, conflict resolution or merge policies). Instead, we contribute the structure-aware substrate such techniques require: a lossless, stable program representation and a deterministic change model that cleanly exposes program locality and identity. This substrate is designed to support a wide range of replication and resolution layers built on top [3, 8, 33].
Paper structure.
Section 2 discusses related work and positions our approach within the context of RCP, synchronization techniques (OT/CRDT), incremental language tooling and parse trees, as well as approaches and algorithms to extract tree operations that drive the core contribution of this paper. Section 3 provides an overview of the structure-aware approach to RCP and defines the proposed LST and SST models, their invariants and our reconciliation heuristics. Section 4 presents a formal edit algebra and a deterministic operation extraction algorithm, and provides proofs of closure and replay correctness. Section 5 describes the proof-of-concept and discusses challenges and how we solved them. Section 6 presents our extensive evaluation and discusses results. Section 7 presents threats to validity. Section 8 concludes and outlines future directions.
2 Related Work
Real-time collaborative programming sits at the intersection of source code maintenance, IDE infrastructure and data consistency. The literature offers strong ingredients, yet none by itself forms a substrate that suffices for a structure-aware real-time collaborative programming environment. Below we trace the most relevant lines of work and derive the requirements they leave unmet for a structure-aware RCP core.
Industry tools and replicated IDEs.
Commercial systems (e.g. Code With Me [21], VS Code Live Share [28], Replit [35]) and research prototypes (CoVSCode [13], CoIDEA [48], CoEclipse [14], CRTC [23]) differ architecturally leveraging host–participant versus fully replicated workspaces. Yet, they share a text-first synchronization layer [30, 13, 48, 14, 23].
Consistency in Synchronous Systems (OT/CRDT).
Operational Transformation and Conflict-free Replicated Data Types are well established for collaborative general text editors [41, 25, 49, 46]. Their operations are defined over sequences or text. Synchronization identities are positional rather than semantic. For code, replication benefits from operations anchored to structural entities with persistent names. The useful takeaways for RCP are thus: (1) edits must be replayable, and (2) those edits should target nodes with stable identities rather than transient character offsets [30].
Incremental IDE tools and parse trees.
Modern IDEs demand a fast code analysis, essentially instantly to preserve a developer’s sense of flow. Tight HCI interaction budgets [29] push editors toward incremental parsing: only the region affected by an edit is reparsed and reanalyzed rather than re-parsing the whole program. Mainstream compilers such as Roslyn (C#) [31], Rowan (Rust) [36] and Swift [44] embody this with persistent, immutable program trees [24]. Roslyn’s Red–Green design, for instance, keeps a compact, immutable lossless green tree and a lightweight red façade. Edits rebuild only the affected path and may hash-cons identical subtrees for efficiency [24]. For compilers, hash-consing identical greens is harmless and efficient. However, when extracting changes in code during tree diffing and replication, it is problematic: two subtrees with the same shape and tokens may collapse to the same instance, so there is no way to distinguish per-occurrence identity. Other incremental parsing approaches, such as Tree-sitter [27], emphasize fast reparsing and broad grammar coverage. Tree-sitter constructs concrete syntax trees of node typees and source ranges, not a self-contained document tree. Lexemes are obtained by slicing the original buffer, and trivia is generally treated as non-structural. As a result, Tree-sitter does not promise a standalone, byte-for-byte round-trip or provide a built-in code-generation (it is a one-way texttree parser). Presented tools were designed for static analysis, not replication: lossless models generally do not publish durable node identities across (re)parses, edit-local updates often do not preserve all source bytes.
Tree differencing approaches.
Classic tree differencing algorithms such as GumTree [11, 10], Zhang–Shasha [51], APTED [34], and ChangeDistiller [19, 15] compute compact, human-readable edit scripts from two snapshots by recovering node correspondences over the whole tree. These scripts are descriptive: node identities are ephemeral and formatting bytes are typically ignored. Replication instead needs prescriptive scripts over persistent ids that preserve trivia so replay prints the exact target bytes.
A related idea appears in React’s virtual DOM reconciliation (Fiber), which uses persistent keys to derive small, deterministic updates to a concrete target [6, 1]. Although our target is source code rather than a browser DOM, the design lesson transfers: maintain a printable concrete tree plus a stable-id overlay, reconcile per parent, and emit deterministic scripts over those ids.
Structure-aware replication: promises and scope limits.
CoAST [30] provides important foundational evidence for the promise of structural approaches to RCP. By defining an AST-based CRDT, it shows that operating over program structure can improve convergence and better preserve user intent than text-based schemes. At the same time, the evaluation assumes a simple Lisp-like subset in which the program is effectively identical to its AST, so concrete syntactic details such as comments and whitespace fall outside the model. The approach uses the GumTree [11, 10] algorithm to derive tree operations between versions, which is reasonable in that restricted AST-only setting, but becomes less practical for larger programs and large file structures, where GumTree does not scale well. Overall, CoAST highlights both the opportunity of structural RCP and the limits of a purely AST-based formulation, motivating a concrete, lossless syntax representation.
Latency and gating.
Human–computer interaction research suggest that local feedback must remain immediate (– s [29]) so the editor never “freezes”, while remote interactions should ordinarily complete within about – s to feel seamless [32]. Empirical reports for RCP indicate that character-wise propagation amplifies lag [52, 45] and exposes collaborators to broken builds; batching at parser-accepted boundaries attenuates both effects [17]. Consequently, the synchronization substrate should be incremental, with commit gating and round-trip guarantees.
3 Structure-aware Approach for Real-time Collaborative Programming
This section introduces the core concept behind our structure-aware, lossless core model and the end-to-end pipeline for RCP. Our core model artifacts (LST, SST, and the edit algebra for operation extraction) and their mechanics follow in subsequent sections.
Core idea.
We treat collaborative editing as replication of program structure, not character streams. The approach maintains a byte-preserving syntax representation and an identity layer that keeps syntactic entities addressable across revisions. From successive accepted program states we then derive a deterministic, replayable change log (edit script). This log is the contract exported to collaboration: it supports efficient replication and provides the stable addressing required by higher-level concurrency control and conflict-resolution layers, which are orthogonal to this paper.
Terminology.
We use round-trip fidelity to mean byte-identical printing of source, including program trivia, like linebreaks, comments and other symbols not covered by ASTs but necessary in source code files. A syntax gate (shown in Figure 2) commits changes only for parser-accepted states. Stable identities are node identifiers that are deterministically reused across revisions and remain unchanged for syntactic entities that are unaffected by an edit. An edit script is the deterministic operation sequence extracted between two program states (details in Section 4).
Operational pipeline.
An overview of the core pipeline is presented in Figure 1. Given a local text delta , we incrementally reparse and apply the syntax gate.
From the accepted parse we (i) materialize the LST, (ii) reconcile SST identities against the previous revision, and (iii) deterministically extract an edit script over SST identifiers.
In a distributed setting, this script is the exported replication contract: replicas apply it to their local SST/LST state and reprint byte-identically, without re-parsing.
Section 4 formalizes the edit algebra, deterministic extraction, and replay semantics, and proves closure and replay correctness. Conceptually this follows state machine replication [37, 38], with edit scripts as the command log and the SST as the replicated state.
We propose the following design goals:
-
Round-trip fidelity. Printing after replay reproduces the target source byte-for-byte.
-
Identity persistence. Unchanged entities retain their SST IDs across revisions; IDs are parent-scoped to keep reuse precise (presented in section 3.2).
-
Determinism. Given the same prior state, applying the extracted script to any replica in state yields the same new state (presented and formalized in section 4).
-
Locality. Unaffected regions remain untouched and small edits yield small edit scripts (evaluated in section 6.2).
-
Language-agnosticism. A lightweight per-language specification (presented in section 3.2.1) configures keying and reconciliation without changing the core.
3.1 Lossless Syntax Tree (LST)
We now instantiate the printable structure introduced before: the Lossless Syntax Tree (LST). An LST node (presented in Figure 3) captures syntax with exact source alignment and formatting, but without turning formatting into structure. We consider an LST to be a labeled ordered rooted tree where nodes may have a string value (text). More formally, let be a Lossless Syntax Tree (LST), a finite set of nodes with distinguished root (). Each node has a parent .
Per-node invariants.
Each node has:
-
(i)
an ordered sequence of children ();
-
(ii)
a grammar kind , where is the finite set of kind labels defined by the language grammar (e.g. class_declaration, identifier);
-
(iii)
byte offsets with ;
-
(iv)
a flag indicating whether the grammar treats this kind as a named node. Anonymous nodes () carry structure but do not denote language entities (e.g. delimiters, separators, operators); and
-
(v)
leaves are exactly those with no children. For a leaf , stores the exact token slice and . For non-leaves we set , where is a distinguished “no value“ sentinel. Formatting bytes not covered by child spans are carried as : inter-child bytes between and are attached to , and bytes after the last child (or when ) belong to .
| kind | : | syntactic kind of the node (defined in the language grammar). |
| startByte | : | inclusive byte offset of the node’s span in the source. |
| endByte | : | exclusive byte offset of the node’s span in the source. |
| isNamed | : | whether the node corresponds to a named grammar symbol. |
| text | : | raw token text for leaf nodes (if any). |
| lead | : | trivia preceding the node within its parent’s span. |
| trail | : | trivia following the node within its parent’s span. |
| children | : | list of child LST nodes in source order. |
Lossless printing contract
Let denote the LST constructed from a parser tree over source buffer and let be the deterministic printer induced by lead/trail and leaf text. We require:
Moreover, rebuilding from the printed bytes yields the same lossless structure againW:
Starting from a concrete parse, we build the LST top-down to satisfy the lossless printing contract. Leaves copy their exact token slice into text. For non-leaves, we iterate children in order while tracking a byte cursor. Bytes not covered by child spans (program trivia) are separated into lead for the next child, with any trailing bytes assigned to the parent’s trail. This ensures all bytes are accounted for without turning formatting into structure and making printing deterministic: at each node we emit lead + subtree + trail. Figure 4 illustrates how trivia in source code maps into our LST.
Attaching trivia to lead and trail, instead of emitting trivia nodes, prevents tiny formatting edits from appearing as structural changes. Formatting motion (whitespace, newlines, comments) becomes a localized payload update on existing nodes rather than insert/delete/move noise that perturbs sibling lists and obscures intent during diffing. This design also makes the lossless printing contract explicit and parser-independent: unlike many off-the-shelf parse trees, which treat trivia inconsistently (often omitting trivia entirely) and typically expose only kinds and byte ranges without storing original lexemes, our LST representation preserves every byte within the tree itself. As a result, replay can reproduce the exact target bytes deterministically without requiring the original source buffer as an external authority. This representation also sets up the SST’s identity layer (presented in Section 3.2) without conflating formatting with structure.
3.2 Stable Syntax Tree (SST)
To turn printable structure into replayable change, we overlay the LST with a Stable Syntax Tree (SST) (Figure 5) that assigns each node a persistent identifier and preserves those identifiers across revisions whenever safe. Intuitively, the SST is the LST plus durable addresses: it mirrors the LST’s child lists exactly (so printing remains byte-identical via the LST), but augments each node with an id, the parentId it currently resides under, and its sibling index. We use a virtual root so that our tree is anchored to a fixed identity – independent of program structure and language. The virtual root’s id is constant across replicas and versions.
SST invariants.
The SST and the LST are in a bijective, order-preserving correspondence (Fig. 5), in which each SST node is associated with exactly one LST node, and the respective child lists coincide elementwise. Each id is globally unique. The fields parentId and index record the current parent and the corresponding 0-based child position, respectively. The tree is rooted at a distinguished virtual root whose identifier is fixed to VROOT_ID.
| id | : | stable identity of the node. |
| lst | : | underlying LST node. |
| parentId | : | id of the parent (if any). |
| index | : | index in parent’s child list. |
| children | : | list of child SST nodes. |
3.2.1 Reconciliation
After an edit we have a previous SST and a next LST . Reconciliation constructs the next SST by assigning each node in either (i) a reused identifier from or (ii) a freshly minted identifier. It returns both and the reused-id set . The procedure is intentionally heuristic and language-guided: it uses a compact language configuration (Section 3.2.1) to define the criterion under which a node is regarded as preserving identity relative to a parent. In cases where the available evidence is inconclusive, the procedure prefers identifier minting over reuse in order to avoid incorrect identity preservation. Accordingly, we impose the following two policies:
1) Parent-scoped reuse.
A node may reuse an id only from candidates that previously occurred under the same parent id (same-parent queues keyed by ). If a parent is newly created, its descendants mint fresh ids. This keeps identities local to their structural context. Cross-parent reuse is disabled for named leaves/trees, with a narrow exception for anonymous delimiter tokens (exact-text, globally unique).
2) Language-guided keys.
Candidate pools are partitioned by a key function derived from the language configuration . Keys encode which syntactic features are stable identifiers in that language (e.g. member names, import paths), while ignoring trivia and other non-identity-bearing structure.
Leaves (tokens)
Leaves carry lexemes and are frequent, reuse must therefore be conservative to avoid spurious renames. Given a leaf-node under a reused parent, we consider same-parent candidates with the same key and apply the following deterministic preference order:
-
Exact-lexeme preference. If the same token text appears among the candidates, we reuse that id. If multiple candidates share the text, we break ties by locality (byte-span overlap, e.g. IoU), preferring the one that stayed in place.
-
Uniqueness guard for named leaves. For identifier- and literal-like leaves, if there is no exact text match, we reuse only when the candidate is uniquely determined under the parent. Example: Consider f(a, b, c) reordered to f(a, c, b) and then renaming c to b, yielding f(a, b, b). Because b is now non-unique under the parent, reusing c’s id for the new b would encode a misleading “cb” update. We instead mint a fresh id for the new b, so the change is expressed as a structural replacement.
-
Anonymous punctuation stability. For delimiters/separators (e.g. (, ), ,), we also use locality to keep punctuation ids stable under small edits, since instability here tends to create diff noise.
Non-leaves (subtrees)
For internal nodes, reuse is primarily about preserving the identity of syntactic entities (declarations, statements, list elements) across local edits. For a non-leaf under a reused parent, we again restrict to same-parent candidates that share and apply:
-
Stable list behavior for containers. For list-/body-like nodes designated as containers by , we reuse identities in a way that preserves existing elements under local insertions (queue in FIFO order). Example: Previous parameters (a, b, c). After inserting at the head: (x, a, b, c). Reconciliation should mint a new id for x while keeping the ids of a, b, and c, so that the subsequent diff emits a single insert rather than cascading replacements.
-
Uniqueness or locality for other non-leaves. If a candidate is uniquely determined by key/kind under the parent, we reuse it. Otherwise we break ties by locality again (byte-span overlap, e.g. IoU), preferring the candidate that remained in place. If ambiguity remains, we conservatively mint a fresh id (with optional language-specific disambiguators in ).
Determinism
All traversal orders and tie-breaks are fixed. Therefore, given the same , all replicas compute the same . Conditioned on , the subsequent diff extraction and replay are fully deterministic and formally specified in Section 4.
Language Configuration for Reconciliation
Our reconciliation logic is language-agnostic but guided by a compact per-language configuration. This section records the contract: how each field affects keying, parent-scoped queues, and matching. Design rationales, trade-offs, and practical implications are examined in the proof-of-concept (Section 5). For each language we configure the following:
-
Containers. Bodies and lists whose identity should not depend on their children. For these kinds we use the coarse key K:<kind> and reuse from the same-parent queue in FIFO order. Examples include program, class_body, and block. Marking these as containers prevents spurious splitting when items reorder and keeps list identity stable under local insertions.
-
Identifiers and named children. Determine how we detect “named leaves“ and identifier-bearing trees. Named leaves get stricter reuse (same-parent, uniqueness checks) to avoid false matches. Examples include identifier and scoped_identifier. This also feeds sibling alignment (same-label pairing) during reconciliation.
-
Delimiters and separators. Declare language token pairs (paren, block, bracket, angle). We use them in two ways: (i) a delimiter-aware signature for matching non-leaf structures with the same surrounding fences, and (ii) to classify anonymous delimiter tokens that may reuse by IoU within a parent or by unique exact text across parents. Separators (e.g. , and ;) similarly identify list punctuation.
-
Non-callable heads. Lists keywords that legally precede “(” but must not be keyed as call-like structures (e.g. if, for, while, …). This avoids conflating control heads with call expressions in head signatures and keeps reuse conservative in statement contexts.
-
Atoms. Mark rare leaf kinds we want to treat as indivisible atoms keyed by content A:<kind>:<text> (e.g. primitive types and literals). This stabilizes these tokens even when their local surroundings shift.
-
Trivia. Declares nodes to ignore during keying and queueing. They do not participate in reuse decisions, which reduces churn from purely formatting-oriented nodes.
-
Semantic keys. Optional, language-aware key functions that override generic shape keys when available. They attach stable, domain-meaningful identities (e.g. fully qualified names, member signatures) to non-container nodes, while still obeying parent-scoped reuse. These keys also enable semantic sibling alignment under a reused parent, improving stability under reorders.
From reconciliation to diffing
Reconciliation gives us a next SST and the set of previous ids reused from . This step fixes node correspondences locally, so the subsequent diffing does not need to re-match whole files: it simply computes a prescriptive edit script over persistent ids that transforms into while preserving the LST’s round-trip invariants. We next formalize the edit script, its operation algebra, and a deterministic extraction procedure.
4 Edit Algebra and Deterministic Diffing of Lossless Syntax Trees
We represent change between SSTs and as an edit script , i.e. a finite sequence of tree edit operations [4, 51, 11]. Edit scripts are prescriptive for replication: replicas replay them without re-parsing or re-matching. Since many distinct scripts can realize the same transformation and shortest scripts with move are NP-hard [11], we favor determinism over global optimality: we restrict move to within-parent reordering and encode relocations as delete+insert, minimizing reorder noise via a deterministic LIS of reused children.
A key separation in our pipeline is that reconciliation (Section 3.2) is language-guided and heuristic. In this section we formalize the remainder of the pipeline. Conceptually, we follow state machine replication [37, 38]. The edit script plays the role of a totally ordered command log, and the SST is the replicated state machine. Reconciliation supplies the correspondence set heuristically, after which both script extraction and replay are fully deterministic: given the same input triple , all replicas derive the same and applying to yields .
Notation
Let be the set of well-formed SST states satisfying the invariants from Section 3.2. For , let be its node identifiers. For , write for its parent id, where denotes the distinguished no-parent marker. The virtual root node has id VROOT and is the unique node with . Let denote its 0-based sibling index, the ordered child list of a parent id , and its lossless payload (lead/trail, and text for leaves). We subscript these functions by the state when needed (e.g. , ).
4.1 Operation schema
We define a small edit algebra over stable node ids, treating each id as denoting either a single node or a node that roots a subtree. Each operation targets a node id (or parent node id) and is interpreted as an update to an SST state. Formally, operations have one of the following forms:
| where is a partial map over . |
Inserts carry fully materialized subtrees (ids and lossless payload) so replicas can replay without re-parsing.
Pre/postconditions
Table 1 summarizes the operational preconditions and postconditions used by replay (e.g. applying ops to the tree and printing it). The SST invariants (child order, indices, and LST/SST mirroring) are preserved after each operation when the preconditions hold.
| Op | Preconditions | Postconditions |
|---|---|---|
| insert | ; ids in are new; | is inserted under at ; all ids in are added; child indices under are contiguous |
| delete | , | subtree rooted at is removed; child indices under are contiguous |
| move | ; ; is not an ancestor of ; | subtree is reattached under at ; indices under old/new parent are contiguous |
| update | ; ; text only if is a leaf | only fields in are overwritten; tree shape/ids unchanged |
4.2 Deterministic diffing
Given , , and the reused-id set as provided by the heuristic reconciliation, our diff procedure computes an edit script . The diff is deterministic and does not search for correspondences. Instead, is the sole source of correspondence and the procedure emits operations in four fixed phases with stable tie-breaking:
-
1.
Top-most deletions. Let be ids present previously but not reused. We emit only top-most deletions , and output for in the stable order induced by sorting on .
-
2.
Top-most insertions. Let be ids newly introduced in the next tree. We emit only top-most insertions , and output for , where is the fully materialized subtree rooted at . Insertions are emitted in the stable order induced by sorting on .
-
3.
Within-parent reordering moves (Longest Increasing Subsequence – LIS). For each parent reused on both sides, let and be the reused children under . Map into positions in and compute a deterministic LIS of the resulting index sequence (e.g. the leftmost LIS produced by patience sorting with fixed tie-breaks). Children in the LIS are treated as kept in order; each other reused child emits .
-
4.
Payload updates. For each reused id , if we emit a single , where contains exactly the fields that differ (and includes text only for leaves). Because formatting is stored in lead/trail rather than trivia nodes, formatting-only changes become localized updates.
4.3 Replay semantics and correctness
Operations (ops) are partitioned by kind and applied in four passes with deterministic internal order. After each structural pass we normalize list separators for the touched parents (to keep punctuation canonical). Let normalize separators for the parent set , with parents processed in lexicographic id order. Define the canonicalization , where is the set of all (non-) parent ids in . Each Apply operation pass deterministically filters and orders the corresponding operations from using rules (1)–(4), then applies them to its input state. Replay is:
where the touched sets are the parents affected in each pass. The pass order and ordering rules are fixed: (1) deletes are grouped per parent, parents sorted by id, and within each parent applied right-to-left; (2) inserts are sorted by ; (3) moves are sorted by ; (4) updates are sorted by node id. As an SST post-condition after each structural step, indices under each parent remain contiguous and consistent with , and the SSTLST child lists remain mirrored.
Lemma 1 (Replay determinism).
For any and any operation sequence such that all steps are defined along the run, is uniquely determined.
Proof.
Each pass applies a set of deterministic operations in a total order and each helper (normalization) is also deterministic. The fixed composition therefore yields a unique result.
Lemma 2 (Diff determinism).
For given inputs , , and , the procedure returns a unique script .
Proof.
Deletions and insertions are defined by set construction plus stable sorting. The LIS step is deterministic under a fixed tie-break (e.g. leftmost LIS from patience sorting). Moves and updates are emitted by iterating in the deterministic DFS order over produced by reconciliation.
Lemma 3 (Replay definedness).
Let and let . Let . Then every operation in satisfies the preconditions in Table 1 at the moment it is applied by . In particular, all steps of are defined.
Proof.
Deletes target exactly , so each deleted node exists and is not VROOT; top-mostness prevents deleting descendants of deleted nodes. For inserts, implies its parent , where is the set of newly introduced ids; hence and is present after deletes; inserted ids are fresh because and all non-reused ids were removed. Moves and updates target only reused ids, so their targets exist throughout replay; moves are within-parent (relocations are delete+insert), so the ancestor constraint holds. Finally, indices used by insert/move are taken from the well-formed and are within bounds. Thus all preconditions in Table 1 hold and replay is defined.
Theorem 4 (Replay-correctness).
Let and . If , then .
Proof.
We argue phase-by-phase. First, deletions remove exactly the subtrees rooted at , which removes precisely the ids in . Second, insertions add exactly the subtrees rooted at ; their ids are exactly , and their structure and payload are carried by the materialized subtree. After these two phases, the id set matches .
Third, for each parent , move operations reorder exactly the reused children under to their target indices . The subsequence selection affects only which children are moved, not the uniquely defined target order taken from . Fourth, updates overwrite exactly the differing payload fields for reused ids, hence matches for all . Separator normalization is deterministic and yields the canonical form. Therefore structure and payload match .
5 Implementation
We implemented our approach as a web-based TypeScript/React application using Monaco Editor. A dedicated web worker runs the full parsereconcilediffreplay pipeline. Therefore, all heavy work executes inside the worker to meet the HCI goal of “respond on keystroke”.
Frontend stack.
We mount the Monaco Editor in a thin component and normalize End-of-Lines(EOLs) to LF (to keep Tree-sitter byte math consistent), and forward editor change batches to the worker. The UI stays responsive: it only updates view state from worker acks. An OpsGraph widget visualizes operation batches over time.
Incremental parsing with Tree-sitter.
We ship Tree-sitter via its wasm (WebAssembly) package and load per-language grammars (Java, JavaScript) in the worker. On each editor change event, we convert line/column ranges to byte offsets, call tree.edit(…), and then reparse incrementally. For robustness, the pipeline is gated when the parse contains ERROR/MISSING nodes: the worker updates the parse tree, but defers LST/SST/diff until the code is syntactically valid.
Language integration.
A compact per-language specification (§ 3.2.1) configures identifiers, container kinds, delimiters, separators, trivia, and optional semantic keys. The specification drives keying and delimiter-aware matching in reconciliation. This keeps the core algorithm (presented in section 3.2.1) language-agnostic while enabling precise reuse.
From TS tree to LST and SST.
The worker converts the Tree-sitter tree to an LST that preserves bytes. We then build an SST with stable ids by parent-scoped reuse, guided by the spec-derived key function.
Diff extraction and replay.
Given the previous and next SST plus the set of reused ids, we produce an edit script based on the formalism presented in Section 4. We do not broadcast operations to real clients. Instead, the app simulates a replica: we clone the previous SST once and apply only operations to that replica. Both the source-of-truth LST and the replica LST are printed back to source code. The UI shows a convergence check () and the last operations applied.
Worker protocol.
The worker exposes four messages: init, set-language, edit, and build. Replies include: buildable (syntax gate), lastOps (recent structural edits), ranges (changed byte windows), and the printed strings (truthPrinted/replicaPrinted). Language metadata is returned on init/set-language to keep the UI dumb and fast.
HCI considerations.
All CPU-intensive steps run off the main thread. The syntax gate prevents expensive work during transient syntax errors, improving perceived latency during fast typing.
Limitations.
The prototype is single-user in the browser: we simulate replication locally and do not implement network transport or real multi-site causality. Nevertheless, this is sufficient for our contribution because all reported invariants and timings concern the local parsereconcilediffreplay pipeline. Network transport and multi-site causality only affect delivery latency and ordering, not the structure or determinism of the generated edit scripts.
Lessons learned
Stabilizing identities in a lossless syntax tree. Lossless Syntax Trees contain many repeated shapes (e.g. multiple field_declarations with identical structure), so identity hinges on the reuse policy. Keys that are too loose cause sibling aliasing after edits (queues “slide” and ids attach to the wrong child), while keys that are too strict turn small changes, like renames, into delete+insert instead of a single update. We obtained stable behavior by combining: (i) parent-scoped reuse (no cross-parent reuse for named entities); (ii) coarse keys for containers and shape/semantic keys for elements; (iii) exact-text reuse for named leaves only under a “unique in both previous and next” rule; and (iv) within-parent moves only (LIS).
Reconciliation trade-offs. Two concrete cases motivated language-specific overrides: (1) Including type_identifier in identifierKinds caused fields such as public MyClass x; and public MyClass y; to be keyed by type rather than name, so a swap paired each declaration with the wrong previous id. Excluding type_identifier and treating types as atoms removed this aliasing. Field identity is now carried by a semantic key on field_declaration (modifiers, type, arity, and name when arity is one). (2) Import edits used to emit delete+insert because the local shape of import_declaration may repeat frequently in Java. A semantic key based on the package path (FQN without the last segment) stabilized identity, turning rename-like changes into a single update.
Language specification dials that mattered. Three parts of the language specification (section 3.2.1) turned out to be the levers that control stability. Containers: key coarsely as K:<kind> so identity lives in elements, not in incidental list/body structure. identifierKinds: use only true entity names (variables, methods, classes), not types; classify types as atomKinds to avoid collapsing sibling declarations onto the same label. semanticKeys: when repetition is inherent, domain keys outperform shape keys (e.g. imports by package path, packages by FQN, fields by mods/type/arity/init/[name]), converting renames into clean updates.
Scoring and guards that reduced mis-reuse. IoU with a parent-shift adjustment handled insertions before a subtree. For tiny wrappers and punctuation, delimiter-aware signatures reliably matched anonymous delimiter tokens. Finally, the “unique in both previous and next” rule for named leaves was a simple guard against b c mispairings during swaps.
Prioritizing determinism for convergence. In a multi-replica editor, convergence beats optimality: reuse decisions and operation emission must be deterministic so replicas derive the same script from the same [46, 39, 2]. We therefore use fixed tie-breaks throughout (including LIS selection). This bias toward determinism prevents replica drift, keeps replay idempotent, and makes caches and snapshot tests stable. A slightly sub-optimal edit (e.g. delete+insert where a perfect move might exist) is cheaper than non-reproducible choices that lead to divergent histories under reordering.
6 Evaluation
Our extensive evaluation is organized around the three research questions presented in section 1. We run the same core pipeline (presented in Fig. 1) across two languages (Java, JavaScript), realistic open-source files, and deterministic edit scenarios. To keep results comparable, all experiments share one harness and one set of conventions for preparing inputs, timing stages, and validating correctness. For each research question we provide specific metrics, discussion of results and implications for our structure-aware approach.
6.1 Global experimental setup
All experiments run the implementation described in Section 5 in a headless environment (Node.js, TypeScript). We use web-tree-sitter with WASM grammars for Java and JavaScript and drive the full pipeline unless the subsection states otherwise. Timing is performed with performance.now(), memory with process.memoryUsage().heapUsed. We run each condition on the same host with no concurrent load.
Corpora and file sizes.
We evaluate two languages (Java, JavaScript) on three real-world OSS files per language (Java: Elasticsearch; JavaScript: Zotero), selected to represent small ( KB), medium (40–75 KB), and large (350 KB–1 MB) inputs. This stratification separates file-size effects from edit-size effects.
Edit scenarios.
We define five deterministic edit scenarios per language (Java, JavaScript) and file (small, medium, large). Edits are applied as source-to-source transforms (not AST/LST rewrites), so the parser, reconciler, and differ see realistic deltas. The scenarios span tiny to large edits and are reused across benchmarks for comparability. All edits preserve syntactic well-formedness.
The scenarios are:
-
keystroke: rename a single identifier (single-token change),
-
line-paste: insert one full line (e.g. a declaration),
-
block-move: move one existing function or statement to a new location within the same parent,
-
mass-delete: delete a larger fragment (e.g. function block/s), and
-
refactoring (multi-region): rename an identifier at multiple distinct use sites within the same file, producing many token-level updates distributed across the syntax tree.
Iterations and aggregation.
We warm up for five iterations and then measure iterations per condition with .
Pipeline metrics.
For end-to-end runs we record build_prev, build_next, diff, and replay and report p95 latency. We use p95 to reflect tail latency relevant to interactive editing while remaining stable at moderate sample sizes. The end-to-end budget is and is compared against the HCI budgets in Section 6.4.
Correctness and reproducibility.
Each run is gated on parser acceptance (no ERROR/MISSING). Edit scripts are validated by replay and byte-identical printing of the resulting LST. The diffing unit test suite (37 tests) serves as a guardrail. Corpora, scenario generators, harness scripts, and raw results are available in our supplemental material: https://doi.org/10.6084/m9.figshare.31368775˜[16]
6.2 RQ1 – Invariants of the Lossless/Stable Tree Model
This subsection evaluates our model to answer the question “Which invariants characterize well-formed program states in a candidate structural model, and how should tokens and trivia be organized to ensure precise round-trip printing and stable node identities across edits?”. We empirically validate the model invariants introduced in Section 3.1–Section 3.2. The operational semantics and the replay-correctness guarantees that justify these validations are formalized in Section 4.
6.2.1 Setup and Execution
We run the full pipeline (Figure 1) for both languages, all file sizes, and all scenarios (including refactoring) with iterations, using the correctness gates from Section 6.1. Each run produces SST states and an edit script and we evaluate invariant checkers on these outputs.
| Lang | Size | Scenario | r_ok | surv. | upd_share | avgLT(p) | avgLT(n) |
|---|---|---|---|---|---|---|---|
| java | s | keystroke | 1.000 | 1.000 | 1.808 | 1.808 | |
| java | s | line-paste | 1.000 | 0.500 | 1.808 | 1.807 | |
| java | s | block-move | 1.000 | 0.667 | 1.808 | 1.808 | |
| java | s | mass-delete | 0.890 | 0.250 | 1.808 | 1.782 | |
| java | s | refactoring | 1.000 | 1.000 | 1.808 | 1.808 | |
| java | m | keystroke | 1.000 | 1.000 | 1.944 | 1.944 | |
| java | m | line-paste | 1.000 | 0.000 | 1.944 | 1.943 | |
| java | m | block-move | 1.000 | 0.667 | 1.944 | 1.944 | |
| java | m | mass-delete | 0.970 | 0.250 | 1.944 | 1.948 | |
| java | m | refactoring | 1.000 | 1.000 | 1.944 | 1.944 | |
| java | l | keystroke | 1.000 | 1.000 | 1.707 | 1.707 | |
| java | l | line-paste | 1.000 | 0.500 | 1.707 | 1.707 | |
| java | l | block-move | 1.000 | 0.500 | 1.707 | 1.707 | |
| java | l | mass-delete | 0.858 | 0.125 | 1.707 | 1.894 | |
| java | l | refactoring | 1.000 | 1.000 | 1.707 | 1.707 | |
| js | s | keystroke | 1.000 | 1.000 | 0.437 | 0.437 | |
| js | s | line-paste | 1.000 | 0.000 | 0.437 | 0.443 | |
| js | s | block-move | 1.000 | 0.750 | 0.437 | 0.431 | |
| js | s | mass-delete | 0.305 | 0.000 | 0.437 | 0.311 | |
| js | s | refactoring | 1.000 | 1.000 | 0.437 | 0.437 | |
| js | m | keystroke | 1.000 | 1.000 | 0.447 | 0.447 | |
| js | m | line-paste | 1.000 | 0.000 | 0.447 | 0.448 | |
| js | m | block-move | 1.000 | 0.000 | 0.447 | 0.447 | |
| js | m | mass-delete | 0.960 | 0.000 | 0.447 | 0.449 | |
| js | m | refactoring | 1.000 | 1.000 | 0.447 | 0.447 | |
| js | l | keystroke | 1.000 | 1.000 | 1.223 | 1.223 | |
| js | l | line-paste | 1.000 | 0.000 | 1.223 | 1.223 | |
| js | l | block-move | 1.000 | 0.500 | 1.223 | 1.223 | |
| js | l | mass-delete | 0.985 | 0.000 | 1.223 | 1.234 | |
| js | l | refactoring | 1.000 | 1.000 | 1.223 | 1.223 |
6.2.2 Metrics
We validate four invariants with executable checkers:
-
I1 – Round-trip fidelity (replay_ok): replaying the edit script and printing yields byte-identical output.
-
I2 – Identity stability (survivor ratio): fraction of pre-edit nodes that keep their IDs.
-
I3 – Parent-local reuse (same-parent rate): among reused IDs, fraction that keep the same parent.
-
I4 – Trivia ownership consistency: per-node lead/trail load remains stable under local edits.
The underlying operation semantics and replay model used by these checks are formalized in Section 4.
6.2.3 Results and Discussion
Table 2 summarizes the invariant checks for both languages.
(I1) Round-trip fidelity.
All runs satisfy replay_ok: replaying the emitted edit-script reconstructs the next state and prints byte-identically. This matches the replay-correctness property proved in Section 4 and confirms that our lead/trail/text payload organization is sufficient for lossless printing in practice.
(I2–I3) Identity stability and parent-local reuse.
Let and be the node-ID sets (excluding the virtual root) in the previous (p) and next (n) SSTs, let be the reused IDs. Write for the parent ID of node in tree .
Survivor ratios are near for keystroke, line-paste, block-move, and the multi-region refactoring scenario, because these edits preserve most structure and therefore reuse the majority of ids. As expected, mass-delete lowers by removing large subtrees. Across all scenarios, including refactoring, , confirming that reuse is parent-scoped; this matches the within-parent move restriction assumed by the deterministic diff in Section 4.
(I4) Formatting isolation and trivia organization.
For a tree , let be its set of nodes. For a node , let and be its owned trivia byte strings, and for any string let denote its byte length. Define the per-node trivia load and summarize trivia distribution as
We also quantify the fraction of an edit script comprised of payload-only edits by
Empirically, and are stable for keystroke, block-move, and refactoring, because these scenarios primarily change leaf text (and at most a few boundary lead/trail fields) without restructuring the tree. line-paste introduces new material and can shift local boundary ownership, while mass-delete removes regions and therefore reduces . This supports our decision to store formatting bytes on nodes (lead/trail) rather than in standalone trivia nodes, so even multi-region renames remain localized updates.
6.2.4 Implications for our structure-aware approach
The presented results show (i) LST’s trivia discipline and leaf-text retention are sufficient for exact round-trip printing; (ii) SST’s parent-scoped IDs yield stable identities and perfect same-parent reuse, enabling deterministic per-parent ordering; (iii) typical developer edits manifest as update plus at most one structural op, avoiding structural noise. Together, these results substantiate the invariants claimed in Section 3.1–3.2 and provide the foundation for the algebra (RQ3 Section 6.3) and determinism (RQ4 Section 6.4) evaluated next.
6.3 RQ2 – Primitive Operations and Canonical Edit Scripts
This subsection evaluates (RQ3): “What minimal set of primitive operations is sufficient to capture edits while preserving closure and deterministic canonical edit scripts?”. Conceptually, this is an empirical validation of the edit algebra and deterministic diff/replay semantics formalized in Section 4: in edit scenarios emitted edit scripts should (i) use only the four primitives, (ii) replay successfully (closure under apply), and (iii) be deterministic and canonical for fixed inputs.
6.3.1 Setup and Execution
We use the same corpora, scenarios, iteration counts, timing methodology, and correctness gates as in Section 6.1. Each condition is additionally run in two modes: with and without the per-parent longest increasing subsequence(LIS) filter used to suppress spurious within-parent reorderings after sibling index shifts. As in Section 4, the filter does not affect correctness (targets are read from ). Instead it affects canonical minimality by selecting which reused children are treated as “kept in order”.
To contextualize edit script sizes against a standard AST differencing baseline, we also run GumTree [11] on the same prev/next sources and extract its operation count per scenario. We use GumTree’s Tree-sitter parser integration [9] to match our setup. GumTree performs explicit node matching and is designed for offline change analysis. Therefore we treat it as a baseline for script size, and discuss timing separately. Comparing end-to-end milliseconds is not meaningful because GumTree always performs full parses of both files and is not intended for real-time replication workloads. Nevertheless, we present GumTree timing breakdowns in Table 4 for context only – yet the numbers may still be useful as a familiar reference point.
6.3.2 Metrics
We use the median operation count (ops_total_median) as a proxy for script minimality, and additionally report the median number of structural operations (ops_struct_median) to separate trivia-only (e.g. update in lead/trail) edits from structural edits. We report diff_p95 and the end-to-end budget to contextualize cost. For GumTree we report (i) actions_count as the script-size baseline in Table 3, and (ii) timings (parse_prev + parse_next + matching + action generation) in Table 4.
6.3.3 Results and Discussion
Scenario results are reported in Table 3. Across all languages, sizes, and scenarios replay succeeds, supporting the operational closure implied by Section 4.
Canonical, scenario-shaped scripts (with the longest increasing subsequence filter). With the filter enabled, scripts closely match developer intent. keystroke yields a single update; line-paste yields one insert (plus at most a small number of boundary updates); block-move yields one move (plus boundary updates); mass-delete yields a small number of top-most deletes. The multi-region refactoring scenario manifests as a small set of updates, demonstrating that the algebra supports non-local, multi-occurrence edits.
Runtime. Per-parent LIS adds matching work, so diff_p95 increases in exchange for canonical, intent-shaped scripts. The median diff_p95 overhead is (Java: , JavaScript: ), while the end-to-end overhead is smaller because parsing and SST construction dominate: the median ratio is (Java: , JavaScript: ). For example, JS/large/line-paste increases from ms to ms in diff_p95, but only increases from ms to ms. Conversely, disabling the minimization causes extreme edit script blow-ups under sibling index shifts, e.g. Java/large/line-paste grows from to operations.
Baseline comparison to GumTree. GumTree’s edit script operations are broadly comparable to ours on simple edits, but differ when our model emits boundary updates to preserve lossless formatting. GumTree operates on ASTs and thus omits trivia ownership.
| Lang | Sz | Scenario | Ops () | Struct () | Diff ms () | Pipe ms () | GT Ops |
|---|---|---|---|---|---|---|---|
| java | s | keystroke | 1/1 | 1/1 | 7.61/3.25 | 63.23/35.07 | 1 |
| java | s | line-paste | 2/21 | 1/20 | 6.03/3.39 | 42.87/43.81 | 1 |
| java | s | block-move | 3/4 | 1/2 | 7.78/3.57 | 66.51/46.08 | 1 |
| java | s | mass-delete | 4/5 | 3/4 | 6.86/2.06 | 57.91/31.44 | 4 |
| java | s | refactoring | 8/8 | 8/8 | 6.45/2.39 | 58.76/30.81 | 8 |
| java | m | keystroke | 1/1 | 1/1 | 17.36/6.62 | 159.43/121.43 | 1 |
| java | m | line-paste | 1/15 | 1/15 | 14.76/6.24 | 205.67/110.79 | 1 |
| java | m | block-move | 3/4 | 1/2 | 16.88/7.18 | 124.57/112.04 | 1 |
| java | m | mass-delete | 4/5 | 3/4 | 11.72/6.52 | 127.89/117.80 | 3 |
| java | m | refactoring | 5/5 | 5/5 | 11.70/7.24 | 113.87/97.31 | 5 |
| java | l | keystroke | 1/1 | 1/1 | 137.48/55.52 | 1217.43/1072.76 | 1 |
| java | l | line-paste | 2/204 | 1/203 | 156.53/105.23 | 1393.97/1362.16 | 1 |
| java | l | block-move | 2/5 | 1/4 | 97.28/86.16 | 1121.08/1119.96 | 1 |
| java | l | mass-delete | 8/9 | 7/8 | 104.00/46.01 | 940.76/849.98 | 7 |
| java | l | refactoring | 33/33 | 33/33 | 107.19/61.88 | 1140.79/1058.20 | 33 |
| js | s | keystroke | 1/1 | 1/1 | 0.84/0.33 | 9.68/5.64 | 1 |
| js | s | line-paste | 1/10 | 1/10 | 0.85/0.50 | 8.03/7.64 | 1 |
| js | s | block-move | 4/7 | 1/4 | 0.95/0.37 | 6.57/4.17 | 1 |
| js | s | mass-delete | 1/2 | 1/2 | 0.38/0.24 | 4.80/5.67 | 1 |
| js | s | refactoring | 12/12 | 12/12 | 0.70/1.48 | 6.73/6.51 | 12 |
| js | m | keystroke | 1/1 | 1/1 | 10.18/6.81 | 90.48/96.36 | 1 |
| js | m | line-paste | 1/6 | 1/6 | 16.54/6.56 | 160.60/96.96 | 1 |
| js | m | block-move | 1/3 | 1/3 | 15.00/5.45 | 113.89/79.32 | 1 |
| js | m | mass-delete | 6/6 | 6/6 | 9.16/6.01 | 86.97/95.27 | 6 |
| js | m | refactoring | 6/6 | 6/6 | 10.98/5.03 | 96.85/85.48 | 6 |
| js | l | keystroke | 1/1 | 1/1 | 699.45/284.18 | 2856.08/2323.75 | 1 |
| js | l | line-paste | 1/18 | 1/18 | 678.23/338.59 | 2775.24/2599.58 | 1 |
| js | l | block-move | 2/3 | 1/2 | 746.92/271.77 | 2865.60/2358.23 | 1 |
| js | l | mass-delete | 2/2 | 2/2 | 726.47/264.96 | 2874.05/2287.45 | 2 |
| js | l | refactoring | 5/5 | 5/5 | 744.70/310.53 | 2802.38/2300.03 | 5 |
| Lang | Sz | Scenario | GumTree (ms) | Our (ms) | ||||
|---|---|---|---|---|---|---|---|---|
| parse_prev | parse_next | match | actions | total | ||||
| java | s | keystroke | 948.46 | 921.07 | 130.24 | 28.24 | 2028.01 | 63.23 |
| java | s | line-paste | 937.55 | 931.28 | 13.02 | 12.39 | 1894.24 | 42.87 |
| java | s | block-move | 950.02 | 924.43 | 7.86 | 11.02 | 1893.33 | 66.51 |
| java | s | mass-delete | 940.35 | 895.25 | 15.69 | 25.62 | 1876.91 | 57.91 |
| java | s | refactoring | 1218.15 | 1006.00 | 13.52 | 5.63 | 2243.30 | 58.76 |
| java | m | keystroke | 2901.04 | 2917.53 | 38.06 | 21.33 | 5877.95 | 159.43 |
| java | m | line-paste | 2809.02 | 2751.93 | 26.38 | 14.96 | 5602.29 | 134.97 |
| java | m | block-move | 2779.80 | 2760.46 | 24.04 | 16.15 | 5580.45 | 124.57 |
| java | m | mass-delete | 2773.00 | 2731.14 | 20.79 | 13.73 | 5538.67 | 127.89 |
| java | m | refactoring | 2978.33 | 3016.91 | 19.83 | 16.29 | 6031.36 | 113.87 |
| java | l | keystroke | 54508.92 | 53706.73 | 245.79 | 166.85 | 108628.28 | 1217.43 |
| java | l | line-paste | 68036.19 | 75628.30 | 283.91 | 212.51 | 144160.91 | 1396.97 |
| java | l | block-move | 65709.83 | 54592.86 | 271.43 | 207.94 | 120782.06 | 1121.08 |
| java | l | mass-delete | 56257.25 | 15375.29 | 261.85 | 352.59 | 72246.98 | 940.76 |
| java | l | refactoring | 53825.04 | 56102.43 | 247.88 | 162.25 | 110337.60 | 1140.79 |
| js | s | keystroke | 165.47 | 166.76 | 1.47 | 0.78 | 334.47 | 9.68 |
| js | s | line-paste | 169.65 | 158.00 | 1.13 | 0.66 | 329.44 | 8.03 |
| js | s | block-move | 195.36 | 179.78 | 1.06 | 0.69 | 376.89 | 6.57 |
| js | s | mass-delete | 159.01 | 179.83 | 1.09 | 1.25 | 341.18 | 4.80 |
| js | s | refactoring | 183.77 | 175.69 | 5.30 | 0.84 | 365.60 | 6.73 |
| js | m | keystroke | 474.42 | 519.06 | 21.04 | 29.14 | 1043.65 | 90.48 |
| js | m | line-paste | 509.23 | 533.09 | 12.85 | 24.69 | 1079.86 | 160.60 |
| js | m | block-move | 499.09 | 522.80 | 17.07 | 25.97 | 1064.94 | 113.89 |
| js | m | mass-delete | 468.31 | 438.04 | 12.43 | 20.58 | 939.36 | 86.97 |
| js | m | refactoring | 450.40 | 456.21 | 23.66 | 29.02 | 959.29 | 96.85 |
| js | l | keystroke | 7872.49 | 7313.09 | 362.82 | 1190.48 | 16738.88 | 2856.08 |
| js | l | line-paste | 7737.31 | 7144.06 | 333.03 | 966.59 | 16181.00 | 2775.24 |
| js | l | block-move | 7382.75 | 7021.62 | 262.96 | 1144.22 | 15811.55 | 2865.60 |
| js | l | mass-delete | 7371.16 | 7491.22 | 298.06 | 1154.25 | 16314.69 | 2874.05 |
| js | l | refactoring | 7522.02 | 6811.83 | 304.08 | 998.04 | 15635.97 | 2802.38 |
6.3.4 Implications for our structure-aware approach
Results indicate that (i) the four primitives {insert, delete, move, update} suffice to capture edits and, per RQ2, remain closed under replay; (ii) per-parent LIS is necessary for canonical minimal scripts under sibling shifts; (iii) LIS’s runtime cost is small relative to the whole pipeline and pays for itself by producing short, intent-shaped, deterministic scripts.
6.4 RQ3 – End-to-End Latency and Structure Sensitivity
This subsection addresses RQ4: “Can a structure-aware approach (incremental parsing, structural matching, and replica replay) meet established HCI response-time budgets, and how do program/tree-structure properties (e.g. node count, maximum sibling fanout, depth) influence those latencies across languages and edit scenarios?”
6.4.1 Setup and Metrics
We evaluate the end-to-end collaboration pipeline, measuring from the first parser-accepted state to the moment replicas apply the change. For each (language, size, scenario) we record p95 for build_prev, build_next, diff, and replay, plus shape statistics (nodes, depth, max fanout). Our lens is perceived responsiveness, guided by classic HCI response-time guidance (Miller and Nielsen’s 0.1–1–10 s rule [29, 32]). Because interactive editing is more stringent, we judge all results against the following budgets:
-
Upper comfort (p95):
-
Hard cap (rare spikes, p99):
| Lang | Size | Scenario | Nodes | Depth | mF | b(p95) [ms] | d(p95) [ms] | d [ms/10k] |
|---|---|---|---|---|---|---|---|---|
| java | s | keystroke | 4666 | 18 | 40 | 38.60 | 7.61 | 16.31 |
| java | s | line-paste | 4674 | 18 | 40 | 26.38 | 6.03 | 12.90 |
| java | s | block-move | 4666 | 18 | 40 | 42.76 | 7.78 | 16.67 |
| java | s | mass-delete | 4151 | 18 | 40 | 34.51 | 6.86 | 16.53 |
| java | s | refactoring | 4666 | 18 | 40 | 38.67 | 6.45 | 13.82 |
| java | m | keystroke | 14371 | 23 | 75 | 103.07 | 17.36 | 12.08 |
| java | m | line-paste | 14379 | 23 | 75 | 84.42 | 14.76 | 10.26 |
| java | m | block-move | 14371 | 23 | 75 | 77.83 | 16.88 | 11.75 |
| java | m | mass-delete | 13938 | 23 | 75 | 87.21 | 11.72 | 8.41 |
| java | m | refactoring | 14371 | 23 | 75 | 74.77 | 11.70 | 8.14 |
| java | l | keystroke | 80117 | 604 | 281 | 826.18 | 137.48 | 17.16 |
| java | l | line-paste | 80125 | 604 | 281 | 980.04 | 156.53 | 19.54 |
| java | l | block-move | 80117 | 604 | 281 | 792.66 | 97.28 | 12.14 |
| java | l | mass-delete | 68772 | 35 | 281 | 598.34 | 104.00 | 15.12 |
| java | l | refactoring | 80117 | 604 | 281 | 794.17 | 107.19 | 13.38 |
| js | s | keystroke | 689 | 27 | 19 | 6.28 | 0.84 | 12.19 |
| js | s | line-paste | 696 | 27 | 19 | 4.23 | 0.85 | 12.21 |
| js | s | block-move | 689 | 27 | 19 | 3.87 | 0.95 | 13.79 |
| js | s | mass-delete | 209 | 6 | 15 | 2.28 | 0.38 | 18.18 |
| js | s | refactoring | 689 | 27 | 19 | 4.12 | 0.70 | 10.16 |
| js | m | keystroke | 12206 | 28 | 101 | 56.91 | 10.18 | 8.34 |
| js | m | line-paste | 12213 | 28 | 101 | 106.23 | 16.54 | 13.54 |
| js | m | block-move | 12206 | 28 | 101 | 67.70 | 15.00 | 12.29 |
| js | m | mass-delete | 11722 | 28 | 95 | 54.50 | 9.16 | 7.81 |
| js | m | refactoring | 12206 | 28 | 101 | 56.34 | 10.98 | 9.00 |
| js | l | keystroke | 251335 | 50 | 854 | 1657.33 | 699.45 | 27.83 |
| js | l | line-paste | 251342 | 50 | 854 | 1554.17 | 678.23 | 26.98 |
| js | l | block-move | 251335 | 50 | 854 | 1590.10 | 746.92 | 29.72 |
| js | l | mass-delete | 247478 | 50 | 852 | 1591.88 | 726.47 | 29.35 |
| js | l | refactoring | 251335 | 50 | 854 | 1558.34 | 744.70 | 29.63 |
6.4.2 Results and Discussion
All scenarios (Table 5 and Figure 6) show tight linear scaling of end-to-end building and diffing time with tree size, but they differ in structure and in diff cost per node. JavaScript trees are shallow but wide (max fanout), whereas Java trees are deep but narrow. Diff cost scales with sibling list width: wider lists increase per-parent alignment work (LIS), though the effect is weaker once normalizing by node count. Using the LIS-enabled per-scenario averages, medians (p95, per 10k nodes) are ms for JavaScript and ms for Java. Fanout still matters after normalization, but unevenly by language: across all 30 points, fanout and d/10k correlate strongly (Pearson ), while the relationship is weak in Java () and strong in JavaScript (). Build time remains primarily a function of overall node count and dominates end-to-end latency for large files, while the diff stage exhibits strong structure-sensitivity. Results show that all Java large scenarios are around or above 1 s, while all JavaScript large scenarios exceed the 2 s budget (2.78–2.87 s). For small and medium sizes, all scenarios remain well below the 1 s p95 budget.
6.4.3 Implications for meeting the HCI budgets
For large files, the limiting factor is build_next, not diff. Three engineering levers follow: (i) windowed SST rebuild, e.g. reuse unchanged subtrees wholesale instead of re-wrapping the whole tree; (ii) persistence of stable wrappers under parents that reconcile unchanged; (iii) commit gating and coalescing of micro-edits into parser-accepted windows to reduce how often the pipeline runs.
7 Threats to Validity
We discuss threats to internal, construct, and external validity, and summarize both the current evidence and the remaining limitations.
Internal validity. Timing and memory measurements of the evaluation may be affected by the JavaScript engine (JIT warmup, inline caching), the WebAssembly runtime, and garbage collection. To reduce variance, we warmed up each benchmark, used repeated runs (), reported p95, and executed all runs on the same host with no concurrent load. Residual noise from GC, OS scheduling, and hidden caches may still bias short stages by a few milliseconds. Our end-to-end timing also excludes network transport and editor UI rendering. In this paper, end-to-end refers to parse LST SST diff replay inside the worker process. At the same time, this controlled setup isolates the algorithmic core of the approach and shows that the dominant costs are already visible without network effects, which is useful for guiding the next optimization steps.
Construct validity. Identity stability is summarized by survivor ratio and same-parent rate. These metrics reflect our parent-scoped reuse policy, but they do not capture all notions of semantic equivalence. Likewise, update_share is a useful proxy for formatting isolation, but not a direct measure of how developers perceive structural noise. Our structure-sensitivity analysis currently operationalizes portability mainly through node count, maximum sibling fanout, and depth. This captures an important part of the algorithm’s behavior, because reconciliation and LIS are driven by local sibling structure, and the evaluation already shows that fanout is more influential than depth. However, other program and grammar characteristics may also matter, including the distribution of sibling-list widths, repeated local shapes, wrapper-heavy grammars, and cross-parent restructuring patterns. Thus, the current evaluation does not close the question of language-agnosticity, but it does establish a concrete and measurable starting point: the main structural drivers can be exposed, quantified, and related directly to the reconciliation heuristics.
External validity. Results are based on two languages and three file sizes. Java and JavaScript are both delimiter-rich, block-structured languages with mature Tree-sitter grammars. The approach is therefore not yet validated for layout-sensitive languages, macro-heavy languages, or grammars with substantially different structural conventions. More generally, the effectiveness of reconciliation may depend on how clearly a language exposes stable cues such as identifiers, delimiters, containers, and trivia classes in the language specification. Nevertheless, the present results are encouraging for portability as the same generic reconciliation algorithm, edit algebra, and replay machinery were applied across both languages using only a compact per-language specification. This suggests that the main challenge is not redesigning the algorithm per language, but understanding which grammar and program characteristics most affect stable reuse and runtime.
A related limitation is that our evaluation is file-local. Cross-file edits involving imports, type resolution, macro expansion, or build-system effects are out of scope.
Reliability and reproducibility. The harness executes deterministic source transforms and validates replay by byte-identical printing. We pin grammar versions and run all experiments in a fixed environment. Unit tests (37 cases) exercise updates, inserts, deletes, moves, and punctuation handling, and we formalize diffing and printing determinism. Reproducibility across engines, platforms, or future grammar revisions may still vary. To mitigate this, we published corpora, scenario generators, harness scripts, version pins, and raw results in the project repository. This does not eliminate all sources of variation, but it makes the current results inspectable and provides a basis for extending the evaluation to additional languages and environments.
8 Conclusion and Future Work
This paper introduced a structure-aware synchronization substrate for real-time collaborative programming that propagates syntactically valid changes rather than unstructured keystrokes. The approach combines two complementary representations and a propagation algorithm: a Lossless Syntax Tree (LST) that preserves byte-identical source text, a Stable Syntax Tree (SST) that adds persistent node identifiers across changes, and a deterministic extraction procedure that derives replayable structural edit scripts using the operations insert, delete, move, and update. Together, these components turn successive program states into deterministic structural changes that can be replayed at collaborators while preserving formatting and source code structure.
The two core design choices – parent-scoped ID reuse and within-parent moves only (minimized via Longest Increasing Subsequence) – make edit scripts canonical and intent-shaped while keeping algorithms simple and predictable. In support of these claims, we provide a formalization of operation semantics and proofs of diffing determinism, replay determinism, and replay correctness for the proposed replay semantics. Empirically, the results align with this design. (RQ1) The model’s invariants hold across languages, sizes, and scenarios: replay prints byte-identically, survivor ratios are with perfect same-parent reuse, and trivia bytes remain stable under local edits. (RQ2) The proposed edit algebra suffice; enabling per-parent LIS is necessary for canonical minimality under sibling shifts, and edit scripts are deterministic across repeated runs. (RQ3) End-to-end medians meet the HCI target for small/medium files and large Java scenarios are close; large JavaScript exceeds the 2 s hard-cap band primarily due to rebuilding a new SST(build_next). Diffing cost is structure-sensitive – increasing with maximum sibling fanout in tree nodes – but is not dominant at scale.
These findings show that a structure-aware approach can take unstructured text changes and extract structural edit operations that preserve code correctness and better reflect developer intent. The resulting substrate is deterministic and language-portable, requiring only a compact per-language specification to guide stable node reuse. In this way, the work separates structural propagation from unstructured keystrokes while providing a practical basis for structure-aware real-time collaborative programming. This lays the groundwork for future consistency layers that can use the substrate to make more informed and structurally meaningful decisions in the automatic conflict resolution that real-time collaborative programming requires.
Future Work.
We will lower tree-build latency via incremental SST rebuilds keyed to dirty spans, targeting p95 1 s on large, wide files. Additionally, we will broaden language coverage to layout-sensitive (e.g. Python) languages, and stress-test large modules to evaluate how far the language-spec dials generalize. We will make the edit script the OT/CRDT convergence layer over SST identifiers, and evaluate bandwidth and replay idempotence under reordering, benchmarking against text-based approaches. Finally, we plan developer studies to assess perceived responsiveness and situational awareness versus text-based RCP, and to explore which commit gates (e.g. parser-accepted boundaries, debounce windows, or semantic checkpoints) best align with developer intent and typical workflows in RCP.
References
- [1] Dan Abramov and Andrew Clark. React fiber architecture. https://github.com/acdlite/react-fiber-architecture, 2017. Accessed: 2025-10-03.
- [2] Paulo Sérgio Almeida, Ali Shoker, and Carlos Baquero. Delta state replicated data types. Journal of Parallel and Distributed Computing, 111:162–173, 2018. doi:10.1016/J.JPDC.2017.08.003.
- [3] Guilherme Cavalcanti, Paulo Borba, Leonardo dos Anjos, and Jonatas Clementino. Semistructured merge with language-specific syntactic separators. In Proceedings of the 39th IEEE/ACM International Conference on Automated Software Engineering, pages 1032–1043, 2024. doi:10.1145/3691620.3695483.
- [4] Sudarshan S Chawathe, Anand Rajaraman, Hector Garcia-Molina, and Jennifer Widom. Change detection in hierarchically structured information. Acm Sigmod Record, 25(2):493–504, 1996. doi:10.1145/233269.233366.
- [5] Kattiana Constantino, Shurui Zhou, Mauricio Souza, Eduardo Figueiredo, and Christian Kästner. Understanding collaborative software development: An interview study. In Proceedings of the 15th international conference on global software engineering, pages 55–65, 2020.
- [6] React Contributors. React documentation. https://react.dev/, 2025. Accessed: 2025-10-28.
- [7] Mark Day. What synchronous groupware needs: Notification services. In Proceedings. The Sixth Workshop on Hot Topics in Operating Systems (Cat. No. 97TB100133), pages 118–122. IEEE, 1997. doi:10.1109/HOTOS.1997.595193.
- [8] Jinhao Dong, Jun Sun, Yun Lin, Yedi Zhang, Murong Ma, Jin Song Dong, and Dan Hao. Revisiting the conflict-resolving problem from a semantic perspective. In Proceedings of the 39th IEEE/ACM International Conference on Automated Software Engineering, pages 141–152, 2024. doi:10.1145/3691620.3694993.
- [9] Falleri et. al. Gumtree tree-sitter parser. https://github.com/GumTreeDiff/tree-sitter-parser, 2026. Accessed 2026-02-04.
- [10] Jean-Remy Falleri and Matias Martinez. Fine-grained, accurate and scalable source differencing. In Proceedings of the IEEE/ACM 46th International Conference on Software Engineering, pages 1–12, 2024.
- [11] Jean-Rémy Falleri, Floréal Morandat, Xavier Blanc, Matias Martinez, and Martin Monperrus. Fine-grained and accurate source code differencing. In Proceedings of the 29th ACM/IEEE International Conference on Automated Software Engineering, ASE ’14, pages 313–324, New York, NY, USA, 2014. Association for Computing Machinery. doi:10.1145/2642937.2642982.
- [12] Hongfei Fan. Any-time collaborative programming environment and supporting techniques. PhD thesis, Nanyang Technological University, Singapore, 2013. doi:10.32657/10356/54902.
- [13] Hongfei Fan, Kun Li, Xiangzhen Li, Tianyou Song, Wenzhe Zhang, Yang Shi, and Bowen Du. Covscode: a novel real-time collaborative programming environment for lightweight ide. Applied Sciences, 9(21):4642, 2019.
- [14] Hongfei Fan and Chengzheng Sun. Achieving integrated consistency maintenance and awareness in real-time collaborative programming environments: The coeclipse approach. In Proceedings of the 2012 IEEE 16th International Conference on Computer Supported Cooperative Work in Design (CSCWD), pages 94–101. IEEE, 2012. doi:10.1109/CSCWD.2012.6221803.
- [15] Beat Fluri, Michael Würsch, Martin Pinzger, and Harald Gall. A retrospective of changedistiller: Tree differencing for fine-grained source code change extraction. IEEE Transactions on Software Engineering, 2025.
- [16] Leon Freudenthaler. Supplemental material: Rcp using lst and sst, April 2026. doi:10.6084/m9.figshare.31368775.
- [17] Leon Freudenthaler, Bernhard Taufner, and Karl M. Göschka. From characters to structure: Rethinking real-time collaborative programming models. In Proceedings of the IEEE/ACM International Conference on Automated Software Engineering (ASE), 2025.
- [18] Akira Fujimoto, Yoshiki Higo, and Shinji Kusumoto. Towards accurate file tracking based on ast differences. In 2021 28th Asia-Pacific Software Engineering Conference (APSEC), pages 553–558. IEEE, 2021. doi:10.1109/APSEC53868.2021.00067.
- [19] Harald C Gall, Beat Fluri, and Martin Pinzger. Change analysis with evolizer and changedistiller. IEEE software, 26(1):26–33, 2009. doi:10.1109/MS.2009.6.
- [20] Felix Grund, Shaiful Alam Chowdhury, Nick C Bradley, Braxton Hall, and Reid Holmes. Codeshovel: Constructing method-level source code histories. In 2021 IEEE/ACM 43rd International Conference on Software Engineering (ICSE), pages 1510–1522. IEEE, 2021. doi:10.1109/ICSE43902.2021.00135.
- [21] JetBrains. Code with me, 2025. Accessed: 2025-10-27. URL: https://plugins.jetbrains.com/plugin/14896-code-with-me.
- [22] Martin Kleppmann, Dominic P Mulligan, Victor BF Gomes, and Alastair R Beresford. A highly-available move operation for replicated trees. IEEE Transactions on Parallel and Distributed Systems, 33(7):1711–1724, 2021. doi:10.1109/TPDS.2021.3118603.
- [23] Stanislav Levin and Amiram Yehudai. Collaborative real time coding or how to avoid the dreaded merge. arXiv preprint arXiv:1504.06741, 2015. arXiv:1504.06741.
- [24] Eric Lippert. Persistence, façades and roslyn’s red-green trees. Accessed: 2025-10-03. URL: https://ericlippert.com/2012/06/08/red-green-trees/.
- [25] Geoffrey Litt, Sarah Lim, Martin Kleppmann, and Peter Van Hardenberg. Peritext: A crdt for collaborative rich text editing. Proceedings of the ACM on Human-Computer Interaction, 6(CSCW2):1–36, 2022. doi:10.1145/3555644.
- [26] Yifan Ma, Batu Qi, Wenhua Xu, Mingjie Wang, Bowen Du, and Hongfei Fan. Integrating real-time and non-real-time collaborative programming: Workflow, techniques, and prototypes. Proceedings of the ACM on Human-computer Interaction, 7(GROUP):1–19, 2023. doi:10.1145/3567563.
- [27] Max Brunsfeld et. al. Tree-sitter is a parser generator tool and an incremental parsing library, 2024. Accessed: 2024-10-25. URL: https://github.com/tree-sitter/tree-sitter.
- [28] Microsoft. Visual studio live share, 2025. Accessed: 2025-10-27. URL: https://marketplace.visualstudio.com/items?itemName=MS-vsliveshare.vsliveshare.
- [29] Robert B Miller. Response time in man-computer conversational transactions. In Proceedings of the December 9-11, 1968, fall joint computer conference, part I, pages 267–277, 1968. doi:10.1145/1476589.1476628.
- [30] Aäron Munsters, Angel Luis Scull Pupo, and Jens Nicolay. Coast: A conflict-free replicated abstract syntax tree. In 17th International Conference on Software Technologies, volume 1 of Proceedings of the 17th International Conference on Software Technologies - ICSOFT, pages 187–196. Scitepress, July 2022. doi:10.5220/0011278800003266.
- [31] .NET Foundation, Microsoft, and contributors. The .net compiler platform (roslyn). Accessed: 2025-10-26; MIT license. URL: https://github.com/dotnet/roslyn.
- [32] Jakob Nielsen. Usability engineering. Morgan Kaufmann, 1994.
- [33] Cyrus Omar, Ian Voysey, Michael Hilton, Joshua Sunshine, Claire Le Goues, Jonathan Aldrich, and Matthew A Hammer. Toward semantic foundations for program editors. arXiv preprint arXiv:1703.08694, 2017. arXiv:1703.08694.
- [34] Mateusz Pawlik and Nikolaus Augsten. Tree edit distance: Robust and memory-efficient. Information Systems, 56:157–173, 2016. doi:10.1016/J.IS.2015.08.004.
- [35] Replit. Replit - The collaborative browser-based IDE. https://replit.com/, 2025. Accessed: 2025-05-22.
- [36] rust-analyzer contributors. Rowan. Accessed: 2025-10-26; Dual-licensed Apache-2.0 or MIT. URL: https://github.com/rust-analyzer/rowan.
- [37] Fred B Schneider. Implementing fault-tolerant services using the state machine approach: A tutorial. Acm Computing Surveys (CSUR), 22(4):299–319, 1990. doi:10.1145/98163.98167.
- [38] Fred B Schneider. Replication management using the state-machine approach. Distributed systems, 2:169–198, 1993.
- [39] Marc Shapiro, Nuno Preguiça, Carlos Baquero, and Marek Zawirski. Conflict-free replicated data types. In Symposium on Self-Stabilizing Systems, pages 386–400. Springer, 2011. doi:10.1007/978-3-642-24550-3_29.
- [40] Leo Stewen and Martin Kleppmann. Undo and redo support for replicated registers. In Proceedings of the 11th Workshop on Principles and Practice of Consistency for Distributed Data, pages 1–7, 2024. doi:10.1145/3642976.3653029.
- [41] Chengzheng Sun and Clarence Ellis. Operational transformation in real-time group editors: issues, algorithms, and achievements. In Proceedings of the 1998 ACM conference on Computer supported cooperative work, pages 59–68, 1998. doi:10.1145/289444.289469.
- [42] Dan Sun, Fan Ouyang, Yan Li, and Hongyu Chen. Three contrasting pairs’ collaborative programming processes in china’s secondary education. Journal of Educational Computing Research, 59(4):740–762, 2021.
- [43] Dan Sun and Fan Xu. Real-time collaborative programming in undergraduate education: A comprehensive empirical analysis of its impact on knowledge, behaviors, and attitudes. Journal of Educational Computing Research, 63(1):33–63, 2025.
- [44] Swift project contributors. Swift programming language, 2025. Accessed: 2025-10-26; Apache-2.0 license. URL: https://github.com/swiftlang/swift.
- [45] Xin Tan, Xinyue Lv, Jing Jiang, and Li Zhang. Understanding real-time collaborative programming: a study of visual studio live share. ACM Transactions on Software Engineering and Methodology, 33(4):1–28, 2024. doi:10.1145/3643672.
- [46] Matthew Weidner and Martin Kleppmann. The art of the fugue: Minimizing interleaving in collaborative text editing. IEEE Transactions on Parallel and Distributed Systems, 2025.
- [47] Jim Whitehead. Collaboration in software engineering: A roadmap. In Future of Software Engineering (FOSE’07), pages 214–225. IEEE, 2007. doi:10.1109/FOSE.2007.4.
- [48] Wenhua Xu, Yifan Ma, Hongguang Zhou, Mingjie Wang, Bowen Du, and Hongfei Fan. A multiple locking group scheme for flexible semantic conflict prevention in real-time collaborative programming. In 2022 IEEE 25th International Conference on Computer Supported Cooperative Work in Design (CSCWD), pages 1432–1437. IEEE, 2022. doi:10.1109/CSCWD54268.2022.9776068.
- [49] Weihai Yu. A string-wise crdt for group editing. In Proceedings of the 2012 ACM International Conference on Supporting Group Work, GROUP ’12, pages 141–144, New York, NY, USA, 2012. Association for Computing Machinery. doi:10.1145/2389176.2389198.
- [50] Weihai Yu. Supporting string-wise operations and selective undo for peer-to-peer group editing. In Proceedings of the 2014 ACM International Conference on Supporting Group Work, pages 226–237, 2014. doi:10.1145/2660398.2660401.
- [51] Kaizhong Zhang and Dennis Shasha. Simple fast algorithms for the editing distance between trees and related problems. SIAM journal on computing, 18(6):1245–1262, 1989. doi:10.1137/0218082.
- [52] Hongguang Zhou, Yifan Ma, Wenhua Xu, Mingjie Wang, Bowen Du, and Hongfei Fan. Context-based operation merging in real-time collaborative programming environments. In 2022 IEEE 25th International Conference on Computer Supported Cooperative Work in Design (CSCWD), pages 1426–1431. IEEE, 2022. doi:10.1109/CSCWD54268.2022.9776234.
