Abstract 1 Introduction 2 Related Work 3 Structure-aware Approach for Real-time Collaborative Programming 4 Edit Algebra and Deterministic Diffing of Lossless Syntax Trees 5 Implementation 6 Evaluation 7 Threats to Validity 8 Conclusion and Future Work References

A Stable Lossless Syntax Tree for Real-Time Collaborative Programming

Leon Freudenthaler ORCID Department of Informatics, Hochschule Campus Wien, Austria
TU Wien, Austria
   Karl Michael Göschka ORCID Institute of Information Systems Engineering, TU Wien, Austria
UAS Technikum Wien, Austria
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 1 second delay budget for small and medium files in both languages. Large Java is near 1 second (p95 1.22 seconds) while JavaScript exceeds the 2 seconds hard-cap (p95 2.86 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 systems
Copyright and License:
[Uncaptioned image] © Leon Freudenthaler and Karl Michael Göschka; licensed under Creative Commons License CC-BY 4.0
2012 ACM Subject Classification:
Software and its engineering Software maintenance tools
; Software and its engineering Collaboration in software development
Supplementary Material:
Software  (Source Code, Evaluation Data and Scripts): https://doi.org/10.6084/m9.figshare.31368775 [16]
Editors:
Robbert Krebbers and Alexandra Silva

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 0.10.2 s) [29], while remote convergence need not be instantaneous but should typically complete within 110 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. 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. 2.

    Canonical, replayable edit algebra: Available AST differencing [20, 18, 51, 34, 19, 15, 10, 11] focuses on offline analysis and human-readable change, not a minimal, deterministic operation set suitable for replication semantics and Lossless Syntax Trees.

  3. 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.

Which invariants characterize well-formed program states in a stable lossless model, and how should tokens and trivia be organized to ensure precise round-trip printing and stable node identities across edits? (defined in Section 3.13.2, evaluated in Section 6.)

RQ2.

What minimal set of primitive operations is sufficient to capture edits while preserving closure and deterministic, canonical edit scripts? (algebra formalization in Section 4, experimental evaluation in Section 6.)

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. 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. 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. 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 (0.10.2 s [29]) so the editor never “freezes”, while remote interactions should ordinarily complete within about 110 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).

Refer to caption
Figure 1: Structure-aware pipeline overview. (1) Local edits are (2) parse incrementally, (3) gate syntax, (4) update the lossless structure (LST), (5) reconcile stable identities (SST), and (6) yield a deterministic, replayable edit script. (7) Replicas apply the script and reprint to byte-identical text.
Refer to caption
Figure 2: Example scenario demonstrating syntax gating and diffing of two Stable Syntax Trees, extracting a delete and an insert operation.
Operational pipeline.

An overview of the core pipeline is presented in Figure 1. Given a local text delta Δt, 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 S yields the same new state S+ (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 T be a Lossless Syntax Tree (LST), a finite set of nodes with distinguished root (root(T)T). Each node tT{root(T)} has a parent parent(t)T.

Per-node invariants.

Each node has:

  1. (i)

    an ordered sequence of children children(t)=c1,,ck (k0);

  2. (ii)

    a grammar kind kind(t)Σ, where Σ is the finite set of kind labels defined by the language grammar (e.g. class_declaration, identifier);

  3. (iii)

    byte offsets start(t),end(t) with start(t)<end(t);

  4. (iv)

    a flag isNamed(t){𝗍𝗋𝗎𝖾,𝖿𝖺𝗅𝗌𝖾} indicating whether the grammar treats this kind as a named node. Anonymous nodes (isNamed(t)=𝖿𝖺𝗅𝗌𝖾) carry structure but do not denote language entities (e.g. delimiters, separators, operators); and

  5. (v)

    leaves are exactly those with no children. For a leaf t, text(t)𝖲𝗍𝗋𝗂𝗇𝗀 stores the exact token slice and |text(t)|=end(t)start(t). For non-leaves we set text(t)=, where is a distinguished “no value“ sentinel. Formatting bytes not covered by child spans are carried as lead(t),trail(t)𝖲𝗍𝗋𝗂𝗇𝗀: inter-child bytes between ci and ci+1 are attached to lead(ci+1), and bytes after the last child (or when k=0) belong to trail(t).

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.
Figure 3: Fields of a Lossless Syntax Tree (LST) node.
Lossless printing contract

Let buildLST(b) denote the LST constructed from a parser tree over source buffer b and let print(T) be the deterministic printer induced by lead/trail and leaf text. We require:

print(buildLST(b))=b.

Moreover, rebuilding from the printed bytes yields the same lossless structure againW:

buildLST(print(T))T.

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.

Refer to caption
Figure 4: Trivia handling in the LST. Highlighted trivia fields inside the tree with corresponding trivia sections in the code snippet.

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.
Figure 5: Fields of a Stable Syntax Tree (SST) node.

3.2.1 Reconciliation

After an edit we have a previous SST S and a next LST L+. Reconciliation constructs the next SST S+ by assigning each node in L+ either (i) a reused identifier from S or (ii) a freshly minted identifier. It returns both S+ and the reused-id set RIds(S). 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 n 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 n under a reused parent, we again restrict to same-parent candidates that share κ𝒞(n) 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 (S,L+,𝒞), all replicas compute the same (S+,R). Conditioned on R, 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 S+ and the set R of previous ids reused from S. 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 S into S+ 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 S and S+ as an edit script ops, 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 ops plays the role of a totally ordered command log, and the SST is the replicated state machine. Reconciliation supplies the correspondence set R heuristically, after which both script extraction and replay are fully deterministic: given the same input triple (S,S+,R), all replicas derive the same ops and applying ops to S yields S+.

Notation

Let 𝒮 be the set of well-formed SST states satisfying the invariants from Section 3.2. For SST𝒮, let Ids(SST) be its node identifiers. For nIds(SST), write par(n)Ids(SST){} for its parent id, where denotes the distinguished no-parent marker. The virtual root node has id VROOT and is the unique node with par(VROOT)=. Let idx(n) denote its 0-based sibling index, child(p) the ordered child list of a parent id p, and payload(n) its lossless payload (lead/trail, and text for leaves). We subscript these functions by the state when needed (e.g. parSST(n), idxSST+(n)).

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:

insert(p,i,sub) :insert subtree at id sub under parent p at index i
delete(n) :delete the subtree rooted at id n
move(n,p,i) :move subtree rooted at id n under parent p at index i
update(n,Δ) :overwrite the fields listed in Δ on id n,
  where Δ is a partial map over {text,lead,trail}.

Inserts carry fully materialized subtrees sub (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.

Table 1: Operation preconditions and postconditions (summary).
Op Preconditions Postconditions
insert(p,i,sub) pIds(SST); ids in sub are new; i[0,|childSST(p)|] sub is inserted under p at i; all ids in sub are added; child indices under p are contiguous
delete(n) nIds(SST), nVROOT subtree rooted at n is removed; child indices under parSST(n) are contiguous
move(n,p,i) n,pIds(SST); nVROOT; n is not an ancestor of p; i[0,|childSST(p)|] subtree n is reattached under p at i; indices under old/new parent are contiguous
update(n,Δ) nIds(SST); Δ{lead,trail,text}; text only if n is a leaf only fields in Δ are overwritten; tree shape/ids unchanged

4.2 Deterministic diffing

Given SST𝒮, SST+𝒮, and the reused-id set RIds(SST)Ids(SST+) as provided by the heuristic reconciliation, our diff procedure computes an edit script ops=diff(SST,SST+,R). The diff is deterministic and does not search for correspondences. Instead, R is the sole source of correspondence and the procedure emits operations in four fixed phases with stable tie-breaking:

  1. 1.

    Top-most deletions. Let D:=Ids(SST)R be ids present previously but not reused. We emit only top-most deletions Dmin:={nDparSST(n)D}, and output delete(n) for nDmin in the stable order induced by sorting on (parSST(n),idxSST(n)).

  2. 2.

    Top-most insertions. Let N:=Ids(SST+)R be ids newly introduced in the next tree. We emit only top-most insertions Nmin:={nNparSST+(n)N}, and output insert(parSST+(n),idxSST+(n),sub(n)) for nNmin, where sub(n) is the fully materialized subtree rooted at n. Insertions are emitted in the stable order induced by sorting on (parSST+(n),idxSST+(n)).

  3. 3.

    Within-parent reordering moves (Longest Increasing Subsequence – LIS). For each parent p reused on both sides, let Cp and Cp+ be the reused children under p. Map Cp into positions in Cp+ 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 c emits move(c,p,idxSST+(c)).

  4. 4.

    Payload updates. For each reused id nR, if payloadSST(n)payloadSST+(n) we emit a single update(n,Δn), where Δn 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 NormP normalize separators for the parent set P, with parents processed in lexicographic id order. Define the canonicalization Canon(SST):=NormPars(SST)(SST), where Pars(SST):={parSST(n)nIds(SST),parSST(n)} is the set of all (non-) parent ids in SST. Each Apply operation pass deterministically filters and orders the corresponding operations from ops using rules (1)–(4), then applies them to its input state. Replay is:

Replay(SST,ops):=(NormPuApplyUpdatesNormPmApplyMovesNormPiApplyInsertsNormPdApplyDeletes)(SST).

where the touched sets Pd,Pi,Pm,Pu 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 (p,i,sub.id); (3) moves are sorted by (p,i,n); (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 childSST(p), and the SSTLST child lists remain mirrored.

Lemma 1 (Replay determinism).

For any SST𝒮 and any operation sequence ops such that all steps are defined along the run, Replay(SST,ops) 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 SST, SST+, and R, the procedure diff(SST,SST+,R) returns a unique script ops.

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 R in the deterministic DFS order over SST+ produced by reconciliation.

Lemma 3 (Replay definedness).

Let SST,SST+𝒮 and let RIds(SST)Ids(SST+). Let ops=diff(SST,SST+,R). Then every operation in ops satisfies the preconditions in Table 1 at the moment it is applied by Replay(SST,ops). In particular, all steps of Replay(SST,ops) are defined.

Proof.

Deletes target exactly DminIds(SST)R, so each deleted node exists and is not VROOT; top-mostness prevents deleting descendants of deleted nodes. For inserts, nNmin implies its parent p=parSST+(n)N, where N:=Ids(SST+)R is the set of newly introduced ids; hence pR and is present after deletes; inserted ids are fresh because NR= 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 SST+ and are within bounds. Thus all preconditions in Table 1 hold and replay is defined.

Theorem 4 (Replay-correctness).

Let SST,SST+𝒮 and RIds(SST)Ids(SST+). If ops=diff(SST,SST+,R), then Replay(SST,ops)=Canon(SST+).

Proof.

We argue phase-by-phase. First, deletions remove exactly the subtrees rooted at Dmin, which removes precisely the ids in Ids(SST)R. Second, insertions add exactly the subtrees rooted at Nmin; their ids are exactly Ids(SST+)R, and their structure and payload are carried by the materialized subtree. After these two phases, the id set matches Ids(SST+).

Third, for each parent p, move operations reorder exactly the reused children under p to their target indices idxSST+(n). The subsequence selection affects only which children are moved, not the uniquely defined target order taken from SST+. Fourth, updates overwrite exactly the differing payload fields for reused ids, hence payload(n) matches payloadSST+(n) for all nR. Separator normalization is deterministic and yields the canonical form. Therefore structure and payload match Canon(SST+).

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 R 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 bc 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 (S,S+,R) [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 (<25 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 N iterations per condition with N=30.

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 T95=build_prev_p95+build_next_p95+diff_p95+replay_p95 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 N=30 iterations, using the correctness gates from Section 6.1. Each run produces (prev,next) SST states and an edit script and we evaluate invariant checkers on these outputs.

Table 2: RQ2 results for Java and JavaScript across sizes and scenarios. We show replay validation (r_ok), survivor ratio (surv.), update share (upd_share), and average per-node trivia load LT¯ (bytes of lead+trail) before (p) and after (n). Same-parent rate is 1.0 in all cells and omitted.
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 IDprev and IDnext be the node-ID sets (excluding the virtual root) in the previous (p) and next (n) SSTs, let RIDprevIDnext be the reused IDs. Write parentS(i) for the parent ID of node i in tree S.

survivor(Sp,Sn)=|R||IDp|,sameParent(Sp,Sn)=|{iRparentSp(i)=parentSn(i)}||R|

Survivor ratios are near 1.0 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 survivor by removing large subtrees. Across all scenarios, including refactoring, sameParent=1.0, 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 S, let N(S) be its set of nodes. For a node n, let lead(n) and trail(n) be its owned trivia byte strings, and for any string x let |x| denote its byte length. Define the per-node trivia load LT(n):=|lead(n)|+|trail(n)| and summarize trivia distribution as

LT¯(S)=1|N(S)|nN(S)LT(n),TBytes(S)=nN(S)LT(n).

We also quantify the fraction of an edit script 𝒪 comprised of payload-only edits by

updateShare(𝒪)=|{o𝒪type(o)=update}||𝒪|.

Empirically, LT¯(S) and TBytes(S) 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 TBytes(S). 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.13.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 SST+). 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 T95=build_prev_p95+build_next_p95+diff_p95+replay_p95 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 2.30× (Java: 2.20×, JavaScript: 2.59×), while the end-to-end overhead is smaller because parsing and SST construction dominate: the median T95 ratio is 1.16× (Java: 1.15×, JavaScript: 1.22×). For example, JS/large/line-paste increases from 338.59 ms to 678.23 ms in diff_p95, but T95 only increases from 2599.58 ms to 2775.24 ms. Conversely, disabling the minimization causes extreme edit script blow-ups under sibling index shifts, e.g. Java/large/line-paste grows from 2 to 204 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.

Table 3: Effect of LIS on script size and tail latency, with GumTree action counts as baseline. Each cell shows /× (LIS on/off). Ops = total operations; Struct = structural ops only; Diff and Pipe are p95 latencies in ms; GT Ops = GumTree action count for the same edit pair.
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
Table 4: GumTree timing breakdown vs. our end-to-end pipeline time. GumTree: full parse + matching + action generation; Our pipeline: total T95.
Lang Sz Scenario GumTree (ms) Our T95 (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): 1s

  • Hard cap (rare spikes, p99): 2s

Table 5: Per-scenario breakdown (LIS enabled). Nodes, depth, and max fanout (mF) from the next tree. Normalized diff is d(p95) per 10k nodes.
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 13.54 ms for JavaScript and 13.38 ms for Java. Fanout still matters after normalization, but unevenly by language: across all 30 points, fanout and d/10k correlate strongly (Pearson r0.885), while the relationship is weak in Java (r0.320) and strong in JavaScript (r0.938). 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.

Refer to caption
Figure 6: Total end-to-end latency (p95) versus next-tree node count. Each point is a (language, size, scenario) condition. Marker size is proportional to the maximum per-parent fanout.

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 (N=30), 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 1.0 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.