Skip to content

Long-document editing measurements ​

This report is for maintainers investigating typing latency and local recovery costs. Use the benchmark to measure both costs before changing recovery behavior.

Run the benchmark ​

After other build and browser checks finish, run these commands from the repository root:

bash
pnpm build
AGMD_BENCH_OUTPUT=/tmp/agentsmarkdown-editing.json \
    node scripts/benchmark-editing.mjs

The benchmark starts an ephemeral local Worker with isolated database, media, and room state. It creates a separate document for each size and surface, then verifies the exact saved text. It does not read or edit production documents.

Each surface receives five warmup inputs and 30 measured inputs. To change the sample count, set AGMD_BENCH_ITERATIONS to an integer from 10 through 200. The benchmark records the Git commit in sourceCommit. For an uncommitted build, set AGMD_BENCH_LABEL to identify the working tree. The runner fingerprints built JavaScript, JSON, and CSS files in builtAppSha256. Build the app again after changing source files.

The performance configuration runs separately from pnpm test:browser. It has no timing pass criteria; environment-dependent timings do not gate normal tests.

Baseline on October 2, 2026 ​

The app measurements use commit 4c77063c4d800401c163ffc84ad53a96f0dbecde. The recovery helper matches that commit. The raw baseline report records every percentile and environment field.

Environment: Apple M3 Max, ARM64, macOS kernel 25.6.0, Chromium 153.0.8010.12, Node.js 26.0.0, and a 1280 × 720 viewport. Each document contains ASCII prose with the caret at its end. Document sizes are decimal bytes: 10 KB, 100 KB, and 1 MB. The benchmark uses one active editor and the local Worker.

Typing latency ​

The browser measurement starts at beforeinput and ends after two animation-frame callbacks. This includes a roughly 33 ms frame interval in this run. The driver measurement also includes Playwright calls and transport overhead. The percentiles use 30 samples per surface:

Document sizeSurfaceBrowser p50Browser p95Driver p50Driver p95
10 KBLive32.2 ms32.8 ms33.4 ms34.5 ms
10 KBSource32.3 ms32.9 ms33.3 ms33.9 ms
100 KBLive31.9 ms33.2 ms33.4 ms34.4 ms
100 KBSource31.2 ms32.6 ms33.3 ms39.3 ms
1 MBLive32.2 ms33.2 ms33.3 ms34.1 ms
1 MBSource32.2 ms33.7 ms33.2 ms34.5 ms

This workload shows no increase in browser input-to-frame latency with document size on this machine. The frame interval limits what these measurements can distinguish. Animation-frame callbacks are a proxy for visual readiness; they do not verify when the display presents pixels.

Local recovery costs ​

The isolated browser measurement uses the app's recovery functions and 30 samples after five warmup inputs. It creates a Yjs document, adds one character, and measures these phases separately:

  1. Read the document text.
  2. Encode the full Yjs state.
  3. Convert the encoded state to base64.
  4. Serialize and retain the draft through createRecoveryController.

The following table records p50 and p95 in milliseconds:

Document sizeFull recovery p50 / p95Yjs encoding p50 / p95Base64 p50 / p95Retention p50 / p95
10 KB0.1 / 0.20.0 / 0.10.1 / 0.20.0 / 0.1
100 KB1.5 / 1.90.1 / 0.21.0 / 1.50.3 / 0.5
1 MB21.5 / 25.31.1 / 1.416.8 / 20.03.7 / 4.0

Text serialization is below the browser timer resolution in these isolated samples. During actual editing, localStorage.setItem alone has a 1.7 ms p95 for 1 MB documents on both surfaces. This storage-only measurement excludes Yjs encoding, base64 conversion, and JSON serialization.

Base64 conversion accounts for most measured recovery work at 1 MB. Preserve synchronous recovery until measurements on slower hardware justify a change. If that work causes missed frame intervals, profile base64 conversion first and preserve the exact recovery bytes when optimizing it.

Review workflow build on October 2, 2026 ​

After the verification checks finished, the benchmark ran twice against the final working tree on codex/review-workflows. Both runs use the same environment, workloads, and sample counts as the baseline. The source base remains 4c77063c4d800401c163ffc84ad53a96f0dbecde; the app includes uncommitted review workflow changes. The labels are final-review-workflows-working-tree and final-review-workflows-working-tree-repeat. Both builds have this SHA-256 fingerprint:

text
942d7fe90a1fd38872c2fabc18df63fe80fde0d13c9887912311037d08ec3021

The first report and repeat report preserve every measurement. The baseline predates build fingerprinting and records its source commit without a build hash.

Typing comparison ​

The following table compares browser input-to-frame timings in milliseconds:

Document sizeSurfaceBaseline p95First run p50 / p95Repeat p50 / p95
10 KBLive32.830.4 / 32.530.3 / 31.8
10 KBSource32.931.2 / 32.431.5 / 32.4
100 KBLive33.230.9 / 32.232.4 / 33.1
100 KBSource32.631.0 / 33.032.4 / 32.6
1 MBLive33.225.2 / 32.232.3 / 33.5
1 MBSource33.726.8 / 32.332.4 / 32.6

Browser p95 remains near the animation-frame interval at every size in both runs. The lower p50 values in the first run do not establish an improvement: frame scheduling limits this measurement, and the repeat differs. Driver p95 ranges from 42.9 through 56.5 ms in the first run and from 33.4 through 94.4 ms in the repeat. The repeat's largest driver p95 occurs in the 10 KB Source document while its browser p95 remains 32.4 ms. Driver timing includes automation and transport overhead, so it cannot isolate app processing time.

Recovery comparison ​

The recovery encoding and controller functions are unchanged from the baseline commit. Full recovery timings in milliseconds are:

Document sizeBaseline p50 / p95First run p50 / p95Repeat p50 / p95
10 KB0.1 / 0.20.2 / 0.40.2 / 0.3
100 KB1.5 / 1.91.4 / 2.31.3 / 2.2
1 MB21.5 / 25.325.4 / 42.623.0 / 28.1

At 1 MB, the phase timings in milliseconds are:

PhaseBaseline p50 / p95First run p50 / p95Repeat p50 / p95
Full Yjs encoding1.1 / 1.41.4 / 3.51.2 / 1.4
Base64 conversion16.8 / 20.019.0 / 21.217.9 / 22.8
Retention3.7 / 4.04.5 / 11.04.0 / 4.2

Actual editor storage-write p95 at 1 MB is 2.6 ms in Live and 2.2 ms in Source in the first run, then 1.5 ms on both surfaces in the repeat. The higher first-run recovery tail is not reproduced at the same magnitude with the same build. These runs show variability and do not identify its cause or establish a regression from the review workflow changes. Base64 conversion remains the largest measured recovery phase. Keep the current recovery behavior, and use this benchmark with slower hardware and fragmented Yjs histories before choosing an optimization.

Limits ​

These results do not represent production networking, mobile hardware, concurrent edits, large tables, component rendering, or documents with fragmented Yjs histories. The isolated recovery measurement separates recovery cost from the app's full editing path; it does not attribute every editing delay to recovery. Browser timer precision and animation-frame scheduling affect small timings. Use the same browser, hardware, source revision, workload, and sample count when comparing runs.

Create and share Markdown documents with people and agents.