What's New Since Udanax-Gold

In 1999, Udanax-Gold was open-sourced — 200,000 lines of mechanically-translated Smalltalk-to-C++ with elegant data structures but no working transclusion queries. Here is everything we built on top.

1. Three-Way Merge for Collaborative Editing 2. Cookie-Based Auth with Signing Keys 3. Cryptographic Provenance 4. Content-Addressed Chunk Store 5. Char-Range Annotations 6. Modern Web Frontend 7. Historical Author & Source Import 8. LLM Integration 9. Club-Based Identity & Security 10. Optimized Transclusion Queries 11. Nelson's 17 Rules: Implementation Status 12. What's Not Yet Implemented 13. Gold Features Not Yet in Xudanu

1. Three-Way Merge for Collaborative Editing

Gold was single-user only. Xudanu supports real-time collaborative editing via otree-merge, a three-way merge that operates directly on O-tree elements — not flattened text. Collaborative edits preserve transclusions, overlays, data bindings, and attribution.

How It Works

When two users edit the same document concurrently, the server performs a three-way merge against a common base:

  1. BLAKE3 fingerprint alignment — identify unchanged segments between three versions
  2. Segment classification — Unchanged, OnlyA, OnlyB, Conflict, Insert
  3. Composable position mappings — positions shift correctly after each merge decision
  4. Conflict-free by default — concurrent inserts at different positions auto-merge
BASE "The quick brown fox" USER A "The swift brown fox" USER B "The quick red fox" THREE-WAY MERGE MERGED "The swift red fox" Both changes preserved — no conflicts, no data loss

Figure 1: Two concurrent edits merged via three-way fingerprint alignment.

pub enum MergeSegment<T> {
    Unchanged(T),
    OnlyA(T),
    OnlyB(T),
    Conflict { a: T, b: T },
    Insert { pos: usize, elements: Vec<T> },
}
Source: The merge engine is in src/edition/three_way.rs. The CRDT manager that wraps it for collaborative editing is in src/server/otree_crdt.rs.

2. Cookie-Based Auth with Signing Keys

Every edit in Xudanu is cryptographically signed with an Ed25519 key. The challenge: how does a web browser hold a signing key? The answer is a carefully designed auth chain where the key is encrypted at rest, decrypted on login, and cached in the server-side session.

Login Flow

  1. POST /auth/login — validates club credentials against Argon2id password hash
  2. Decrypts signing keyauthenticate_with_pending uses Argon2id + ChaCha20-Poly1305 AEAD
  3. Caches in sessionOAuthSession.signing_key_bytes stores the Ed25519 key bytes server-side
  4. Sets HttpOnly cookiexudanu_session cookie with CSRF token provided separately

WebSocket Auto-Auth

  1. Browser sends cookie on WebSocket upgrade request automatically
  2. Server reconstructs SigningKey via authenticate_session_from_oauth from cached bytes
  3. Provenance worksmaterialize_with_provenance finds the key, signs every edit
  4. Public fallbacksession_login_public for anonymous browsing if no cookie present
LOGIN Argon2id verify DECRYPT KEY ChaCha20-Poly1305 CACHE SESSION signing_key_bytes HttpOnly Cookie xudanu_session WebSocket auto-auth via cookie The signing key never leaves the server — the browser only holds a session cookie

Figure 2: Auth chain from login through WebSocket auto-authentication.

OAuth2 support: GitHub and Google OAuth2 login with session cookies via the oauth2 crate v5. Club signing keys are encrypted at rest with Argon2id key derivation + ChaCha20-Poly1305 AEAD. Rate-limited login: 10 attempts per 5 minutes per club.

3. Cryptographic Provenance

Gold had no cryptographic attribution — authorship was asserted, not proven. Xudanu signs every edit with Ed25519. An append-only SHA-256 hash-chained transparency log records every provenance signature, making forgery detectable after the fact.

Three Author Types

TypeColorDetails
HumanGreenEd25519 keypair, display name from club profile. Every keystroke attributed to a verified identity.
LLMPurpleModel name tagged in provenance. AI-generated text visually distinguished. Supports Ollama (local) and OpenRouter (cloud).
HistoricalAmberShakespeare, Austen, etc. Server-signed attestations. Generic external_ids field for authority database lookups (not yet populated).
ElementProvenance {
  signature:   Signature,   // Ed25519
  author_key:  PublicKey,
  author_name: String,
  author_type: AuthorType,
  // Human | Llm | Historical
  timestamp:   u64,
  server_id:   String,
}

// Signature covers:
// BLAKE3(
//   fingerprint
//   || author_key
//   || timestamp
//   || server_id
// )
// with domain separation

Transparency Log

Every provenance signature is recorded in an append-only SHA-256 hash-chained log. Each entry includes the hash of the previous entry — tampering with any single entry breaks the entire chain from that point forward.

ENTRY #1 Alice writes paragraph sha256(prev=null) → hash_a ENTRY #2 Bob transcludes Alice sha256(hash_a) → hash_b ENTRY #3 Claire edits her section sha256(hash_b) → hash_c Each entry includes the hash of the previous entry — tampering breaks the chain

Figure 3: SHA-256 hash-chained transparency log for provenance signatures.

4. Content-Addressed Chunk Store

Gold used in-memory Smalltalk object storage with no persistence. Xudanu stores document content as individually addressable .xchunk files in hex-sharded directories, each verified by BLAKE3 hash. Checkpoints write only changed chunks, not the entire state.

Storage Layout

xudanu-data/
├── chunks/
│   ├── ab/
│   │   └── ab3f...c821.xchunk
│   ├── 7e/
│   │   └── 7e2a...f409.xchunk
│   └── ...
├── works/
│   ├── work-001.json
│   └── ...
├── manifest.json
└── audit.log

Properties

PropertyHow
DeduplicationIdentical content stored once (content-addressed via BLAKE3)
Hex-sharded directoriesFirst 2 hex chars of BLAKE3 hash determine the subdirectory
Incremental checkpointsWrite only changed chunks, not entire state
LRU cacheCapacity 1024 for hot chunks in memory
Atomic writestmp file + rename prevents corruption on crash
BLAKE3 verificationEvery chunk verified on read by hash comparison
Garbage collectionOrphaned chunks cleaned up alongside annotation cleanup
Off-site backupbackup-chunks.sh syncs immutable chunks + manifests to a remote server via rsync/SSH. Content-addressed design makes incremental backup safe — chunks are write-once, BLAKE3 hash = filename.
Backup gaps: The backup script intentionally excludes blobs (binary objects) and server keys (private key material). For full disaster recovery, blobs need a separate sync and the server's Ed25519 keypair needs out-of-band transfer (e.g. manual scp or a secrets manager). Completing federation would provide automatic multi-node replication as an alternative.
Source: The chunk store is implemented in src/persist/. The manifest with annotations_hash field is in src/persist/manifest.rs. The backup script is at examples/backup-chunks.sh.

5. Char-Range Annotations

A full CRUD annotation system operating on character ranges. Yellow highlights in the editor, annotation panel with author attribution, keyboard shortcut Ctrl+Alt+A / Cmd+Alt+A. Annotations are a metadata layer — they don't modify document content — so they work on source works too.

pub struct Annotation {
    id:              String,
    doc_id:          String,
    start:           usize,    // char offset
    end:             usize,    // char offset
    text:            String,   // annotation body
    color:           Option<String>,
    created_by:      String,   // club ID
    created_by_name: String,   // display name
    created_at:      u64,
}

Features

Source: Annotation CRUD, persistence, and three-way merge support are in src/server/otree_crdt.rs. The frontend annotation panel is in web/app/src/components/AnnotationPanel.tsx.

6. Modern Web Frontend

Gold had a terminal/Motif UI. Xudanu has a React SPA with TypeScript, real-time collaborative editing via WebSocket, canvas-based attribution overlays, and side-by-side comparison with bridge curves connecting transcluded regions.

Components

ComponentWhat It Does
EditorcontentEditable with canvas overlay for provenance colors, transclusion markers, and annotation highlights. pointer-events: none when no overlays — cursor placement always works.
CompareSide-by-side document comparison with bridge curves connecting transcluded regions. Shared (amber), left-only (blue), right-only (orange). Edit while comparing — highlights update live.
Source ViewerRead-only source work display with smooth scrolling (5 lines/tick wheel normalization). Green "pub src" badge. Annotations overlay supported.
AnnotationsYellow highlight selection, annotation panel with CRUD, author names. Keyboard shortcut Ctrl+Alt+A.
PrivacyDocuments default to private ("PRIV" badge). Share menu toggles public/private. Signed-out users see only public works.
Deep LinksSPA with ?work=<id> query param and #L<line> / #C<char> hash deep links. No react-router.

Wire Protocol

110+ operation codes covering sessions, clubs, works, editions, links, transclusion, blobs, overlays, labels, retrieval, attribution, search, shared content, range queries, versioning, recorders, crypto, endorsements, federation, membership, governance, and CRDT sync. Dual codec: binary (LEB128 + postcard) and JSON.

7. Historical Author & Source Import

Pattern-based detection for Project Gutenberg, Internet Archive, and plain text. Registry for non-digital authors with external IDs. Content boundary detection to skip header/footer boilerplate. Source works are permanently frozen — no edits allowed. Content matching on paste automatically attributes provenance to historical authors.

Source Import Flow

  1. Detect format — Project Gutenberg headers, Internet Archive metadata, or plain text
  2. Extract boundaries — skip boilerplate header/footer, identify actual content
  3. Register author — match to existing historical author or create new (with optional external IDs)
  4. Freeze work — mark as source (immutable), public by default
  5. Attribution on paste — when pasted content matches a source work, provenance automatically attributed to the historical author
Historical authors receive server-signed attestations. Since Shakespeare doesn't have an Ed25519 keypair, the server signs on his behalf using its own key, with the author type set to Historical and the external ID recorded.
External IDs not yet wired in. The data model has a generic external_ids: HashMap<String, String> field for authority database lookups, and both VIAF and LoC expose free public APIs that return stable IDs from an author name (e.g. VIAF AutoSuggest returns viafid and lc IDs). However, the ImportWizard does not yet call these APIs — the field is always empty. This is a natural enhancement for the author creation step.

8. LLM Integration

Multi-backend support for AI-assisted editing. All LLM output is cryptographically tagged in the provenance system with AuthorType::Llm and the model name.

FeatureDetails
Local modelsOllama integration for running models on the developer's machine
Cloud modelsOpenRouter and GitHub Models for cloud-based LLMs
Diff narration"Summarize changes" between two document versions
Auto-title generationGenerate document titles from content
Writing feedbackOn-demand feedback and suggestions
Provenance taggingAll LLM output tagged with model name and AuthorType::Llm in the provenance system

9. Club-Based Identity & Security

Personal "clubs" with Ed25519 keypairs encrypted at rest. Gold had no concept of user identity or access control.

Security Features

FeatureImplementation
Key encryption at restArgon2id key derivation + ChaCha20-Poly1305 AEAD
Password hashingArgon2id with PHC-string format
Rate limiting10 login attempts per 5 minutes per club
OAuth2GitHub and Google login via oauth2 crate v5
CSRF protectionCSRF token required on WebSocket connections
Audit logSHA-256 chained tamper-evident log of security events
Session cookiesHttpOnly, validated on every request
Threat classificationThreat-level classification for security events
Password policyMinimum 10 chars, mixed case + digit (client + server enforced)

Federation with Byzantine Fault Tolerance

Encrypted peer channels (X25519 + ChaCha20-Poly1305). OrSet and LwwRegister CRDTs for state reconciliation. PBFT governance for membership and policy decisions. Cross-server transclusion queries. Transport layer exists; content sync is incomplete. Once finished, federation would provide automatic multi-node replication — an alternative to the manual off-site backup script for data redundancy.

10. Optimized Transclusion Queries

The Udanax team designed elegant data structures but left core queries unimplemented. The BackfollowEngine had no callers. H-tree canopy flags were allocated but never checked. Xudanu connects the pieces and makes them fast.

OperationNaive (C++ parity)XudanuHow
Find works containing textO(W × L)O(U × A)Fingerprint HashMap intersection, no full scan
Find shared regions (diff)O(n × m)O(La + Lb)Fingerprint seed discovery + greedy claiming
Edition element listingO(n log n) every callO(1) after firstOnceLock cache shared via Arc
Transclusion index lookupO(n) flat scanO(log n)H-tree canopy-filtered traversal
Position transform (shift)O(n) rewriteO(1)Lazy Dsp node wraps tree without traversal
Region highlightingO(r × t)O(r + t)Sorted regions, single pass

W = works, L = text length, U = unique fingerprints, A = avg works/fingerprint, n/m = doc lengths, r = regions, t = text

Key insight: BLAKE3 content fingerprints give us inverted indexes (fingerprint → works), intersection (shared content), and pruning (canopy flags) — all from the same hash. The O-tree's content-addressing IS the optimization.

11. Nelson's 17 Rules: Implementation Status

How closely does Xudanu implement Ted Nelson's original 17 Rules of Xanadu? Here is the honest accounting.

#RuleStatus
1Every document consists of arbitrarily many portionsDone — O-tree elements
2Every portion can be transcludedDone — inline RangeElement::Transclusion, 32-level recursive resolution
3Permission is required to transcludeDone — club-based ACLs
4Permission is required to quoteDone — source import + attribution
5Tumbler addressingPartial — Id/IdSpace, no full tumbler paths
6Bidirectional linksDone — HyperLink/HyperRef
7Visible on both sidesDone — backlinks + Related footer (always-visible)
8Identical content stored onceDone — GrandMap + BLAKE3
9Royalty at any granularityPartial — data structures exist, no payments
10Mix of royalty-bearing and free contentPartial — endorsement types exist
11Data available from any serverPartial — federation transport, incomplete sync
12Connection by any protocolPartial — WebSocket only
13Adaptive storage tieringNot started
14Redundant storagePartial — local checkpoint + off-site backup script for chunks/manifests. Federation transport exists but content sync incomplete
15Charge users at any rateNot started
16Handle any data typePartial — 9 element types, no structured editing UI
17Portable front-endPartial — web SPA, no mobile
6
Fully Done
9
Partially Done
2
Not Started

12. What's Not Yet Implemented

Features from Ted Nelson's original vision that remain to be built.

Content & Editing

FeatureStatusWhat Exists
Live transclusion renderingShippedInline RangeElement::Transclusion in the O-tree CRDT with 32-level recursive resolution and cycle detection. Transcluded fragments render inline with live updates.
Compound documentsShippedInline transclusion in the O-tree (single source of truth — no side-table drift). Compound tutorial exists. Span migration through arbitrary deltas.
Trails and guided pathsShippedTrailsPanel provides trail builder UI with create, reorder, remove, navigate, and publish. Curated document sequences with categories.
Inter-span linksPartialLinks at work-level only. No (work, edition, start, end) targeting
Three-way visual diff UIPartialBackend has three_way_diff() and three_way_merge(). No visual character-level diff UI
Full-text searchPartialfind_text_transcluders does fingerprint search. No general inverted-index search across all works

Infrastructure

FeatureStatusWhat Exists
Royalty/micropayment systemPartialStorageCost, CostMethod, cost() fully implemented. No payment flow or billing system
Adaptive storage tieringNot startedAll data on local filesystem. No hot/cold migration
Geographic replicationPartialCrash-safe checkpoint + off-site backup script (backup-chunks.sh) for immutable chunks/manifests via rsync. Federation transport exists but content sync incomplete. Blobs and server keys excluded from backup — need separate handling.
Export / interchange formatNot startedNo way to export works to a portable format
Version genealogy UIPartialAPI operations exist (version_ancestors, version_descendants). No UI
Non-destructive archivePartialWorkIrrevocablyUnpublish is destructive. No soft-delete or is_archived flag

Known Limitations

13. Gold Features Not Yet in Xudanu

Features present in the Udanax-Gold C++ codebase (~200,000 lines) that have no equivalent or only stubs in Xudanu.

Content Model

FeatureWhat Gold HadWhat Xudanu Has
Tumbler / Sequence addressingFull Sequence positions (1.2.3.4) with interval regions, prefix queries, edge types (INCLUSIVE, EXCLUSIVE, PREFIX)Simple Vec<i64> — no hierarchical addressing or prefix queries
Multi-dimensional coordinate spacesIntegerSpace, RealSpace, SequenceSpace, IDSpace, CrossSpace, FilterSpace with full mapping/ordering subsystemsPartial implementations in src/space/RealSpace and FilterSpace are stubs
CrossRegion endorsementsEndorsements as multi-dimensional CrossRegion over IDSpace × EndorsementSpace with projection and set operations. Per-region endorsements within editions.Flat BTreeSet<Endorsement> — edition-wide only, no cross-space operations
Edition structural operationscombine(), replace(), stepper(Region, OrderSpec), isRangeIdentical(), makeRangeIdentical(), mapSharedOnto(), sharedWith()with()/without() for single-position ops. three_way_diff() for text only. No structural Edition-level merge or identity unification.
PlaceHolder / FillDetectorPlaceHolder as a RangeElement for template slots. FillDetector fired async when slots were filled. Background transclusion resolution.PlaceHolder in the enum but never created — no fill detection, no templates
Recursive transclusion (again())RangeElement::again() returned the element this was a transclusion of, supporting recursive chainsNo equivalent
IDHolder (in-content references)IDHolder as a RangeElement wrapping an ID — editions could contain pointers to other objects inlineWorkRef/EditionRef variants exist but are not first-class RangeElements
OverlaysCompositional layers on editions with resolution pipelineRangeElement::Overlay in enum — no overlay resolution or rendering

Identity & Access Control

FeatureWhat Gold HadWhat Xudanu Has
Recursive club membershipClubDescription with Set of member clubs. Clubs could contain clubs with recursive resolution.Flat clubs — no nesting, no delegation
Work sponsorsSeparate sponsor relationship — clubs that vouched for a work's existenceNo sponsor concept — only read/edit clubs
Work history clubSeparate historyClub controlling access to revision historyHistory visible to anyone with read access
KeyMaster authority delegationAccumulated authority from multiple logins, incorporate() to merge, removeLogins() to revokehas_authority() checks only — no merge or delegation
ID batch allocationIDSpace::global()/unique(), BatchCounter for preallocating ranges on disk, GrantTable for club-scoped allocationSimple sequential u64 — no batch preallocation or grants

Protocol & Infrastructure

FeatureWhat Gold HadWhat Xudanu Has
Link type sets and named endsHyperLink with Set of link types, endNames(), MultiRef with set operationsSimple links — no type sets, no named ends, no MultiRef
Persistent agenda / task queueAgenda/AgendaItem surviving crashes. Sequencer for ordered composition. Background transclusion resolution.All operations synchronous — no deferred work, no crash-surviving task queue
Comm protocol negotiationPortal for bidirectional channels, Negotiator for version negotiation, BootPlan for connection setupSingle WebSocket protocol — no version negotiation, no multi-transport
Recent versions (v0.9.5 – v1.0.0):