oficina / docs Public

Clone
git clone https://amadan.net/oficina/docs

Plain git — no account needed to clone.

Download

Download this file

1# Native replica typing probe — 2026-09-13
2
3This bounded review experiment exercises the real `CRDTReplica` actor and its
4statically linked WASM host. It is not a UI responsiveness, device, release-build,
5or web/native performance parity benchmark. No production algorithm was changed.
6The executable was an arm64 macOS Swift debug test build. Other integration work
7was running on the machine, so these single samples are directional evidence.
8
9| Mode | Characters | Elapsed seconds | Snapshot bytes | Total emitted update bytes | Largest update bytes | Client IDs |
10| --- | ---: | ---: | ---: | ---: | ---: | ---: |
11| Fresh presentation after every character | 100 | 1.221 | 1,635 | 1,802 | 27 | 101 |
12| Fresh presentation after every character | 1,000 | 26.734 | 15,901 | 17,867 | 27 | 1,001 |
13| Fresh presentation after every character | 5,000 | stopped, no completed sample | — | — | — | — |
14| Fresh presentation after each 100-character batch | 100 | 0.014 | 159 | 127 | 127 | 2 |
15| Fresh presentation after each 100-character batch | 1,000 | 0.120 | 1,192 | 1,178 | 127 | 11 |
16| Fresh presentation after each 100-character batch | 5,000 | 0.673 | 5,792 | 5,858 | 127 | 51 |
17| One retained source, individual character commands | 100 | 0.137 | 159 | 1,810 | 28 | 2 |
18| One retained source, individual character commands | 1,000 | 1.813 | 1,060 | 19,755 | 28 | 2 |
19| One retained source, individual character commands | 5,000 | 11.442 | 5,060 | 99,755 | 28 | 2 |
20
21The fresh-source mode acknowledges each presentation immediately and retires the
22old generation before the next publication. The retained-source control never
23publishes another presentation, approximating a burst whose callbacks still refer
24to one displayed generation; it is not a proposed safe replacement algorithm.
25Batch mode inserts 100 ASCII characters per command and then presents. All modes
26start with one paragraph and assert the resulting text length at every milestone.
27Wall time includes actor commands, internal snapshots/projections, source retention,
28and (where specified) presentations and their selection-anchor resolution. It
29excludes initial open/paragraph creation, network, native text layout, and rendering.
30Milestone snapshot/client queries add a little work to subsequent cumulative times.
31
32Per-character new client IDs materially increase work and persisted CRDT overhead
33in this workload. At 1,000 characters the fresh-source snapshot is 15,901 bytes,
34about 0.19% of the 8 MiB bridge boundary. The bridge does not expose an encoded
35state-vector command, so exact vector bytes were not measured. For these fresh
36workloads, client IDs and clocks fit unsigned 32-bit varints: a conservative
37encoded-vector bound is `5 + 10 * clientCount` bytes (five bytes each for ID and
38clock plus five for count). That is at most 10,015 bytes for the measured 1,001
39clients. This is a bound, not an observed size or a long-document capacity claim.
40Latency becomes material well before the measured byte boundary. Rich formatting,
41large documents, long sessions, peer updates, and device memory limits remain
42unmeasured; batching is not validated here as a correctness-preserving fix.
43
44The first 5,000 fresh-generation run was stopped after roughly four minutes to
45release SwiftPM's build lock for integration. SwiftPM buffered its XCTest output,
46so no completed 5,000 result or intermediate metrics were recovered. The smaller
47fresh-source sample and both controls were then run directly with `xctest`, which
48does not hold the SwiftPM lock and emits milestones immediately. A separate 100
49character sample took 1.244 seconds with a 1,638-byte snapshot/101 clients; small
50size differences reflect randomly assigned client IDs.
51
52## Repeating the probe
53
54`NativePerformanceProbeTests.swift` is intentionally outside the normal test
55source tree. Temporarily copy it into `native/apple/Tests/DocsKitTests/`, build the
56test bundle once with a 100-character limit, and remove the copied source after
57measurement. Use the actual built test-bundle path for your machine:
58
59```sh
60DOCS_PROBE_MODE=fresh DOCS_PROBE_COUNT=100 swift test --package-path native/apple --filter NativePerformanceProbeTests
61DOCS_PROBE_MODE=fresh DOCS_PROBE_COUNT=1000 /Applications/Xcode.app/Contents/Developer/usr/bin/xctest -XCTest DocsKitTests.NativePerformanceProbeTests/testTypingProbe native/apple/.build/arm64-apple-macosx/debug/DocsNativePackageTests.xctest
62```
63
64Set mode to `batch` or `retained` and count to `5000` for the controls. Run modes
65sequentially and bound runtime. Recorded executable SHA-256:
66`3ce4222fa0981fc444f85bb858cdebca921eecf26c5eb50d4e44657ed62b2485`.
67Original local logs: `/private/tmp/docs-probe-fresh1000.log`,
68`/private/tmp/docs-probe-batch.log`, `/private/tmp/docs-probe-retained.log`.
69
70## Acknowledged identical-source reuse followup
71
72After the independently reviewed `presentation(..., allowReuse: true)` change,
73mode `reuse` explicitly acknowledges the current published generation before every
74next character and requests reuse. Every character still performs a presentation
75and selection-anchor resolution. Only the same live source with byte-identical
76committed state can be returned; this does not batch away commands or render steps.
77
78| Characters | Elapsed seconds | Snapshot bytes | Total update bytes | Largest update | Client IDs |
79| --- | ---: | ---: | ---: | ---: | ---: |
80| 100 | 0.329 | 159 | 1,810 | 28 | 2 |
81| 1,000 | 3.303 | 1,060 | 19,755 | 28 | 2 |
82| 5,000 | 30.845 | 5,060 | 99,755 | 28 | 2 |
83
84The 1,000-character sample falls from 26.734 to 3.303 seconds (about 8.1 times
85faster in these individual runs), with client count bounded at two. The 5,000
86sample now completes, but there is no completed pre-change 5,000 timing to form a
87ratio. It remains slower than the retained-source control, which omits all
88presentation/anchor work, and much slower than 100-character batches. These data
89support reduced source churn; they do not establish a device latency budget or
90solve the cost of projecting and snapshotting long documents on every keystroke.
91The source-reuse regression separately proves peer divergence and undo still
92publish fresh generations and preserve peer content, and default/no-acknowledgement
93calls still use fresh sources.
94
95This followup was also measured amid integration builds. Its initial separate
96100-character compile-phase sample took 2.727 seconds, versus 0.329 seconds in the
97direct run, demonstrating machine-load sensitivity. The table is the single direct
98run's cumulative milestones, not selected best timings. Direct log:
99`/private/tmp/docs-probe-reuse5000.log`. Repeat using `DOCS_PROBE_MODE=reuse`.
100Followup executable SHA-256:
101`b08998210ac83bec46a8cb2d62c51c0e2792b0c65e647f52fa58eaee879a3c55`.
102