Generated benchmark JSON and trace files stay outside version control. The
scripts below write to ignored test-results/ paths by default; local archives
use the ignored benchmark-results/ directory. This document retains the
measurement summaries, including failed runs, and reproduction commands.
All five final production NVCA runs at application revision af634f9 pass the
strict 150 ms input-response gate across all nine phases. The largest
observed response is 144 ms. The module, studio, profiled studio, late-body,
and footnote workloads retain their original targets and editing assertions.
Runs were serial, with other local work paused and no application changes within
the five-run matrix.
| Maximum observed input response | Module | Studio | Studio, profiled | Late body, profiled | Footnote, profiled |
|---|---|---|---|---|---|
| Five ordinary interaction phases | 96 ms | 72 ms | 64 ms | 96 ms | 144 ms |
| Collapsed Enter | 104 ms | 120 ms | 136 ms | 96 ms | 80 ms |
| Original styled pause/resume phase | 24 ms | 48 ms | 24 ms | 40 ms | 32 ms |
| Explicit run-boundary styled typing | 24 ms | 48 ms | 48 ms | 48 ms | 32 ms |
| Explicit interior styled typing | 24 ms | 104 ms | 48 ms | 24 ms | 32 ms |
| Full 150 ms gate | Pass | Pass | Pass | Pass | Pass |
The unmodified docxodus@12.6.2 and matching export companion resolve the
leading-tab formatted-insertion exclusion through the supported atomic API.
The previously blocked footnote interior phase falls from 816 ms on 12.6.1 to
32 ms in the final run. Two React-side changes address additional blocking
work found after the upgrade:
- Incoming document parsing and sanitization wait for idle input, yield during traversal, and discard superseded preparation. Width readiness uses a delivered ResizeObserver measurement, avoiding a forced full-document layout inside the setup task. Pagination resumes in a separate browser task. In the traced footnote pause/resume comparison, all incoming setup tasks shrink from 55.5–80.9 ms to 15.5–20.5 ms, with no style/layout events inside the new setup tasks. Layout still occurs separately.
- Canvas anchor resolution reuses the native formatting read instead of scanning every document anchor after a version change. Canonical formatting aliases share cached results and invalidate together; story identity and native transaction guards remain enforced. A preceding 152 ms Enter trace included 13.3 ms scanning anchors and 86.2 ms rendering changed blocks. The minimal canvas contract now performs zero full anchor scans before Enter's first frame; the final profiled module Enter windows also contain none. Other studio controls still use the inventory where needed.
The follow-up included fourteen runs: four diagnostic traces, five runs after the preparation change, and five final runs after the anchor lookup change. Both intermediate 152 ms Enter failures remain part of these results. Local setup trace excerpts include verified source callsites, task CPU/wall time, layout events, and trace digests. The two original 184 ms events below were not captured again, and their exact causes remain unproven. These later findings do not retroactively attribute them.
Lint, types, library/demo builds, the complete API identity audit, and generated pagination checks pass. All 82 unit tests and 55 browser contracts pass, with two opt-in browser skips; the final application revision's CI is green. Regression coverage includes leading tabs, formatting alias invalidation, and incoming-layout cancellation during real IME composition, preserving text, caret, native versions, and undo behavior.
The full NVCA integrity test and native/cooperative pagination differential both pass: 65 pages, 234 body paragraphs, 110 footnote paragraphs, 13 intentionally modified paragraphs, one added paragraph, and 31 native commits. Save/reopen preserves unrelated paragraph XML, fields, bookmarks, notes, sections, and package parts. Production studio/module smoke tests pass (seven tests, one source-only skip). Packed consumer imports, types, runtime-copy verification, and the Node export API pass. PDF rendering is skipped because this host denies the unprivileged user namespaces required by Chromium's process sandbox.
These are quantized Chrome Event Timing samples on one Intel Core Ultra 7 258V, Linux x64, Chromium 143.0.7499.4, at 1480×1050 without CPU throttling, collected with a 16 ms reporting threshold. They do not establish population INP or an editor-wide maximum. A native call intersecting the rounded event window may begin after the actual paint; an overlap alone does not establish causality. Individual native calls and background layout can exceed 150 ms when no sampled input overlaps them. Structural layout after Enter still takes seconds. Excluded native structures, compound edits, opening, export, and slower devices remain outside the measured 150 ms result.
The initial upgrade pinned the unmodified docxodus@12.6.2 and matching export
companion. Upstream #802 extends the
supported atomic formatted operation to runs with leading tabs, including the
NVCA footnote that caused the remaining 816 ms stall. The full historical
workloads remain the comparison; other excluded structures retain the public
atomic batch. See the 12.6.2 upgrade notes.
Five serial production runs at application revision 357c8b6 retained all nine
extended phases and the same NVCA targets used for 12.6.1. Every run passed its
text, formatting, surrounding-text, key-count, and Enter-undo checks.
| Maximum observed input response | Module | Studio | Studio, profiled | Late body, profiled | Footnote, profiled |
|---|---|---|---|---|---|
| Five ordinary interaction phases | 88 ms | 56 ms | 48 ms | 56 ms | 184 ms |
| Collapsed Enter | 64 ms | 80 ms | 120 ms | 96 ms | 72 ms |
| Original styled pause/resume phase | 24 ms | 24 ms | 24 ms | 64 ms | 56 ms |
| Explicit run-boundary styled typing | 48 ms | 24 ms | 24 ms | 88 ms | 56 ms |
| Explicit interior styled typing | 72 ms | 40 ms | 24 ms | 184 ms | 64 ms |
| Full 150 ms gate | Pass | Pass | Pass | Fail | Fail |
The previously blocked footnote interior phase improved from 816 ms to 64 ms. Its two formatted native calls took 53.8 and 41.6 ms, with no transaction setup, package hash, or native page-map registration in that phase. The supported operation preserves the tab and original text formatting.
The strict 150 ms gate failed in two of the five original runs. Both 184 ms observations are primarily time queued before the key handler. The late body keyup waited 172.2 ms before the first native commit in that phase; no instrumented native call or recorded Long Task overlaps its delay. The footnote pause/resume keydown waited 163.3 ms during an unattributed 168 ms Long Task, also without an overlapping native call. A later 289.1 ms native formatted call in the late-body phase is outside the failed event's time window and does not explain that delay.
Two diagnostic repeats added CPU profiles and paused other tool work during measurement. No application code changed:
| Maximum observed input response | Late body, CPU profile | Footnote, CPU profile |
|---|---|---|
| Entire nine-phase workload | 96 ms | 80 ms |
| Explicit interior styled typing | 24 ms | 16 ms |
| Full 150 ms gate | Pass | Pass |
The outliers did not reproduce in these repeats, so their internal cause remains unproven. The repeats do not replace the failures: five of all seven runs pass. An after-run observation of other host CPU activity is insufficient to attribute either delay to contention. Local diagnostic records retain every phase, both failed event windows, native call summaries, and source/profile digests. These are quantized Chrome Event Timing samples on one Intel Core Ultra 7 258V, Linux x64, Chromium 143.0.7499.4, at 1480×1050 without CPU throttling; they do not establish population INP or an editor-wide maximum. Individual native calls and background layout can exceed 150 ms even when no sampled key overlaps them. Structural layout after Enter still takes seconds. Excluded native structures, compound edits, opening, export, and slower devices remain limits.
Two fresh native contexts isolated the original NVCA footnote run containing
w:tab followed by w:t, inserting at offset 24. The atomic formatted operation
now succeeds in 29.5–32.7 ms, compared with the 600.2–621.9 ms fallback on
12.6.1. Only ReplaceTextAtSpanWithFormat executes for the edit. Both contexts
also pass ordinary body insertion (67.9–69.9 ms), exact typed formatting,
surrounding formatting, tab/reference count/order/attributes/text positions,
one-version atomicity, and one-step undo/redo. Undo restores XML after equivalent
namespace prefixes are normalized.
Lint, types, library/demo builds, the complete API identity audit, and generated pagination checks pass. All 82 unit tests and 53 browser contracts pass, with two opt-in browser skips; the application revision's CI is green. The new browser cases cover one and two leading tabs; the excluded hyperlink case still verifies the atomic fallback.
The full NVCA integrity test passes with 65 pages, 234 body paragraphs, 110 footnote paragraphs, 13 intentionally modified paragraphs, one added paragraph, and 31 native commits. Save/reopen preserves unrelated paragraph XML, fields, bookmarks, notes, sections, and package parts. Native and cooperative pagination match for pages, HTML, and fragment maps on the same fixture. The production studio and module pages pass seven smoke tests with one source-only skip. Packed consumer imports, types, runtime-copy verification, and the Node export API pass. PDF rendering is skipped because this host denies the unprivileged user namespaces required by Chromium's process sandbox.
The preceding integration pinned the unmodified docxodus@12.6.1 and matching export
companion. The supported atomic text-plus-format operation now handles interior
insertion in ordinary text runs, resolving
Docxodus #799. Excluded structures
retain the public atomic batch. See the 12.6.1 upgrade notes
for the fallback contract and runtime compatibility.
Five serial production runs at application revision 4273011 covered the
original module/studio workload, a profiled studio run, and profiled runs near
the end of the body and in a late footnote. Each retained all nine extended
phases and passed its text, formatting, surrounding-text, key-count, and
Enter-undo checks.
| Maximum observed input response | Module | Studio | Studio, profiled | Late body, profiled | Footnote, profiled |
|---|---|---|---|---|---|
| Five ordinary interaction phases | 56 ms | 72 ms | 56 ms | 88 ms | 96 ms |
| Collapsed Enter | 64 ms | 152 ms | 104 ms | 104 ms | 40 ms |
| Original styled pause/resume phase | 40 ms | 56 ms | 64 ms | 80 ms | 40 ms |
| Explicit run-boundary styled typing | 48 ms | 32 ms | 56 ms | 64 ms | 40 ms |
| Explicit interior styled typing | 48 ms | 40 ms | 152 ms | 24 ms | 816 ms |
| Full 150 ms gate | Pass | Fail | Fail | Pass | Fail |
The original unprofiled interior typing cases improved from 384–400 ms on 12.6.0 to 40–48 ms. The broader 150 ms goal was unmet at that revision. Both 152 ms observations remain in the results; the profiled studio outlier overlapped a 189.2 ms native formatted operation. That measurement does not isolate the native internal cause of its variability.
The footnote exposes a documented exclusion in 12.6.1: its first text run
contains a leading w:tab and w:t. The caret is inside the text, but the atomic
formatted insertion refuses this mixed-content run. The existing public batch
preserves editing semantics and incurs 199.6 ms for native page-map registration,
274.4 ms for transaction setup, and 284.7 ms for the package hash in this run.
The resumed key waited about 809 ms. Follow-up:
Docxodus #802.
Local diagnostic records retain all five runs, actual target anchors/text, native call summaries, and the overlapping calls for failed gates. These are quantized Chrome Event Timing observations on one Intel Core Ultra 7 258V, Linux x64, Chromium 143.0.7499.4, at 1480×1050 with no CPU throttling. Full structural layout after Enter still takes seconds, separately from its input response. These samples do not establish population INP or an editor-wide maximum; excluded structures, compound edits, opening, exports, and slower devices remain material limits.
A serial batch/formatted/formatted/batch comparison measured the supported formatted replacement at 56.0–56.4 ms for the first edit and 26.6–29.8 ms on repeats. Ordinary warm interior insertion took 28.7–29.1 ms. The legacy batch took 624.3–625.8 ms initially and 523.7–526.9 ms on repeats. All twelve replacement checks and both insertion checks passed, including one-step undo/redo.
Two additional fresh native contexts isolated the real footnote structure. Ordinary interior insertion succeeded in 64.6–68.5 ms. Insertion into the tab/text run was refused in 6.8–6.9 ms without changing its version, XML, or formatting. Its atomic fallback took 600.2–621.9 ms even without React, rendering, or a page map. Text, surrounding formatting, one-version atomicity, and undo/redo passed; undo restored the XML with equivalent namespace-prefix spellings normalized. A subsequent marker integrity check also verified that the edited XML retains the tab and footnote-reference count, order, attributes, and positions relative to the text in both fresh contexts.
Lint, types, library/demo builds, the complete API identity audit, and the generated pagination check passed. All 82 unit tests and 51 browser contracts passed, with two opt-in browser skips; CI for the application revision is green. The full NVCA integrity test passed with 65 pages, 234 body paragraphs, 110 footnote paragraphs, 13 intentionally modified paragraphs, one added paragraph, and 31 native commits. Save/reopen checks preserved unrelated paragraph XML, fields, bookmarks, notes, sections, and package parts. Native and cooperative pages, HTML, and fragment maps matched on the same fixture. The built production studio and module pages passed seven smoke tests, with one source-only skip. Packed consumer imports, types, runtime-copy verification, and the Node export API check passed. PDF rendering was skipped because this host denies the unprivileged user namespaces required by Chromium's process sandbox.
The preceding integration used the unmodified docxodus@12.6.0 and matching export
companion. Its public replaceMatch(match, text, format) handles contiguous
replacements and run-boundary insertions without an outer batch. Styled drafts
retain their original selection so identical spaces and repeated text cannot
shift the formatting span. The existing live session, block rendering, and
cooperative pagination remain in use.
Three serial production runs on application revision 7a2bac5 covered the
standalone module, full studio, and a module run with native-call profiling:
| Maximum observed input response | Module | Studio | Module, profiled |
|---|---|---|---|
| Five ordinary interaction phases | 48 ms | 32 ms | 56 ms |
| Collapsed Enter | 80 ms | 56 ms | 64 ms |
| Styled typing at a run boundary | 24 ms | 24 ms | 16 ms |
| Original styled phase, inside an existing run | 1,184 ms | 376 ms | 376 ms |
| Explicit middle-of-run styled typing | 400 ms | 384 ms | 384 ms |
All text, formatting, surrounding-text, key-count, and Enter-undo checks passed. The full 150 ms gate failed in every run at that revision. The native API accepts a zero-length insertion only at a run boundary. For an interior insertion, the editor must borrow a neighboring character for the text operation and apply formatting only to the new text. Those two operations retain the public atomic batch so existing formatting, rollback, and one-step undo remain correct.
In the profiled run, the first interior insertion paid 95–115 ms for native
page-map registration, 164–171 ms for BeginTransaction, and 169–170 ms for
GetPackageContentHash. The next burst, now at a run boundary created by the
first edit, used ReplaceTextAtSpanWithFormat in 26–28 ms. The unprofiled
1,184 ms outlier was not individually profiled; it remains in the reported
maximum.
A direct probe against the published runtime confirms that an interior insertion
returns offset_out_of_range without changing the native version, text, or run
formatting. The probe used two fresh contexts and another native
batch/formatted comparison.
The supported-API follow-up is Docxodus #799.
These are quantized Chrome Event Timing samples on an Intel Core Ultra 7 258V, Linux x64, Chromium 143.0.7499.4, at 1480×1050 without CPU throttling. They are not population INP or an editor-wide latency guarantee. Full structural layout after Enter completed in 2.07–2.22 seconds in these runs, separately from the 56–80 ms input response.
Validation on this application revision: 82 unit tests and 50 browser contract tests passed in CI (two opt-in skips). The full NVCA integrity test passed with 65 pages, 234 body paragraphs, 110 footnote paragraphs, 13 intentionally modified paragraphs, one added paragraph, and 31 native commits. It independently checked unrelated paragraph XML, fields, bookmarks, notes, sections, and package parts after save/reopen. Native/cooperative pagination also matched on the same NVCA fixture. The built production pages also passed seven smoke tests (one source-only skip). Packed entry points, consumer types, runtime-copy verification, and the Node export API check passed. The PDF render test was skipped because this host denies the unprivileged user namespaces required by Chromium's process sandbox.
The initial follow-up targeted interaction responses under 150 ms. The first changes remove atomic batch/receipt overhead from single-paragraph formatting, share formatting and style reads across controls, preserve cached formatting only for anchors proven unchanged by the native edit journal, and keep page-map notifications from refreshing document-only queries. Normal typing now builds its verified native span from formatting instead of requesting a full Markdown projection for anchor metadata. Caret selection avoids repeated document scans.
In a local Chromium production benchmark of the pinned NVCA document, selected-word Bold improved from about 1.3 seconds to 80 ms event-to-paint. Twenty-four arrow presses caused no additional native formatting queries (previously 72). These first results still left page-map registration and page-flow updates blocking the main thread for hundreds of milliseconds or longer, motivating the cooperative layout work below.
Four serial NVCA production runs on September 13, 2026 (commit 77d1441)
covered the standalone module and full studio twice each, once with native-call
timers and once without. All native text, formatting and surrounding-text checks
passed. The largest observed input response across these runs was 144 ms.
| Interaction | Worst input response across four runs |
|---|---|
| Continuous typing | 24 ms |
| Arrow-key caret movement | 24 ms |
| Pause/resume typing | 144 ms |
| Selected-word Bold | 80 ms |
| Resuming typing during line wrapping | 128 ms |
Selected-word Bold previously reached 1,344 ms in the local module. Line-wrap tasks previously blocked the main thread for 1.5–1.6 seconds; the longest task in these four runs was 160 ms. Continuous typing's key-handler-to-rAF p95 stayed at 15–17 ms. Native formatting reads during 24 arrow presses fell from 72 to zero.
Full reflow is still background work: the final wrap edit took 1.48–1.58 seconds to obtain a current page map, including the 350 ms debounce. Cold opening, exports, large multi-step mutations, and slower devices are not covered by the 150 ms result. An additional explicit-format typing benchmark still reached 1,400 ms: native atomic transactions clone the package and generate a complete receipt/hash. Preserving atomic rollback and one-step undo for compound edits still carries that cost. These results do not establish an editor-wide 150 ms maximum.
A follow-up at 83263f0 removed the unnecessary outer transaction from a
collapsed Enter, retaining native split/undo semantics. The extended benchmark
measured 200 ms for Enter, down from 1,600 ms, and verified native one-step undo.
The original five interaction phases stayed within target on this build's
module and studio repeats (56 ms and 88 ms maxima respectively).
It still exceeded the target: immediate paragraph rendering and style/revision
refreshes accounted for most of the remaining task. Structural edits also need
a full conversion and page-map validation afterward. Styled typing continues to
need a real compound native edit; suppressing its rollback or receipt guarantees
would change the API contract rather than solve that bottleneck.
The subsequent 8f31e4c module run measured Enter at 152 ms after retaining
proven-unchanged style/empty-revision metadata across splits and removing empty
selection deletion reads. The five ordinary phases peaked at 72 ms in this run;
styled typing still reached 1,408 ms. These are single-run observations on that
revision, not a repeated sub-150 ms result. Enter's structural reflow also took
6.93 seconds to finish in the background. Its complete phase included a 351 ms
long task after the input, so the input measurement does not establish a maximum
for every later task.
At 0dad65d, structural edits switched from separate paragraph renders to the
existing native batch renderer. Enter measured 136 ms in the module, but 280 ms
with profiling and 320 ms without it in the studio. The studio trace identified
another 125 ms spent generating the sidebar's full Markdown preview catalog
during the keypress. This motivates deferring that optional catalog while keeping
current native block identities and the selected paragraph's text immediately
available. It also shows why module-only timing cannot establish studio latency.
The 8fd41f7 follow-up uses React's deferred query value for sidebar previews.
In the studio profile, the 126 ms Markdown projection moved after Enter's first
frame instead of extending its input handler. Three serial production runs on
that final application revision measured:
| Interaction | Module, no profiling | Studio, no profiling | Studio, profiling |
|---|---|---|---|
| Largest response in the five ordinary phases | 144 ms | 72 ms | 128 ms |
| Enter response | 112 ms | 152 ms | 160 ms |
| Explicitly styled typing response | 1,496 ms | 1,416 ms | 1,432 ms |
All text, formatting and native Enter-undo checks passed. The full extended
RDV_LATENCY_LIMIT_MS=150 gate failed in every run: styled typing remains above
target, as does Enter in the studio. Enter's complete structural layout took
7.07–7.67 seconds, with later native validation/layout tasks reaching 372 ms.
The module also recorded a 372 ms background task after continuous typing.
These results improve response times without establishing a 150 ms editor-wide
maximum. The remaining compound native transaction cost is tracked upstream below.
The full NVCA integrity test also passed on 8fd41f7: 65 pages, 234 body and
110 footnote paragraphs editable, 13 intentionally modified paragraphs, one added
paragraph, and 31 native commits. Independent package inspection confirmed
unchanged paragraph XML, fields, bookmarks, notes, sections, and unrelated parts.
The source-harness timings use native default Markdown
patches and are not the production input-response metric.
The machine was an Intel Core Ultra 7 258V with eight logical CPUs, Chromium 143.0.7499.4, a 1480×1050 viewport, and no CPU throttling. The module rendered 65 pages; the studio's different profile rendered 52.
npm run test:latency:native isolates compound-edit costs from
React, the editor canvas, rendering, and page-map registration. It imports the
published docxodus core and WASM, opens the same NVCA fixture, replaces one word
in a body paragraph, and applies Bold to the replacement. It compares the default
atomic executeBatch (including its package receipt) against the supported
replaceMatch(match, text, format). emitMarkdownPatch is false.
The script alternates batch/formatted/formatted/batch in fresh browser contexts. Each context measures its first edit and two repeats after undo/redo verification. Only the synchronous editing call's wall time is measured; fixture loading, projection, verification, undo and redo are outside that timer. Native bridge wrappers time the original calls without changing their behavior. Every attempt checks replacement text, Bold, a single version advancement, and text/formatting restoration through one undo and redo. These checks do not replace the full DOCX package integrity suite.
On the published 12.6.0 package, twelve serial attempts on the same machine and Chromium configuration produced:
| 12.6.0 editing API | First edit in each fresh context | Repeats after undo/redo |
|---|---|---|
executeBatch |
560.8–673.2 ms | 410.3–565.0 ms |
replaceMatch(match, text, format) |
52.9–53.0 ms | 24.3–28.0 ms |
All twelve text, formatting, version, undo and redo checks passed, with no browser
errors. The formatted path called ReplaceTextAtSpanWithFormat without
BeginTransaction or GetPackageContentHash bridge calls; batches retained
their receipt hashes. These are native-call timings, not browser input response
times. Both paths in this comparison use the
same 12.6.0 package; the older measurements below are historical context.
Before 12.6.0, twelve serial batch attempts on the published packages reproduced the stall (the earlier harness compared versions rather than editing APIs):
| Package | First batch in each fresh context | Repeats after undo/redo |
|---|---|---|
| 12.4.1 | 1,161–1,168 ms | 991–1,018 ms |
| 12.5.0 | 1,199–1,202 ms | 984–1,010 ms |
Across these attempts, BeginTransaction took 379–501 ms and
GetPackageContentHash took 458–496 ms. Together they took 837–969 ms per batch.
The text replacement and formatting calls together took 46–79 ms. Source
inspection identifies complete-package checkpoint serialization at transaction
begin and again when producing the package equivalence hash. The dependency
upgrade alone did not eliminate this workload's stall; these measurements do not
assess other 12.5.0 improvements or unreleased upstream builds. All twelve text,
formatting, version, undo and redo checks passed, with no browser errors.
The local native benchmark reports contain the unrounded measurements and
package fingerprints. This is a small diagnostic sample, not a percentile or
cross-device latency guarantee.
# From this repository, after npm ci and installing Playwright Chromium:
curl --fail --location \
'https://nvca.org/wp-content/uploads/2025/10/NVCA-Model-COI-10-1-2025.docx' \
--output /tmp/NVCA-Model-COI-10-1-2025.docx
RDV_STRESS_DOCX=/tmp/NVCA-Model-COI-10-1-2025.docx npm run test:latency:nativeTo use an older package for the batch baseline without changing dependencies, use
npm pack docxodus@12.4.1 --pack-destination /tmp, extract its tarball to a separate
directory, and set RDV_NATIVE_COMPARE_ROOT to the extracted package directory.
The formatted operation always uses the installed package. With no comparison
root, both paths use the installed package.
RDV_NATIVE_BENCH_OUTPUT overrides test-results/native-transactions.json.
The report records the fixture, JavaScript and WASM SHA-256 hashes, package
versions, browser, CPU, individual bridge calls and correctness checks. There is
no build or preview server prerequisite for this native-only benchmark.
After the timed replacement attempts, each formatted context measures a warm
interior insertion. Successful insertions must preserve surrounding formatting,
advance the version once, and restore text and runs through one undo and redo.
Rejected insertions must leave the native version and formatting unchanged.
Each formatted context also probes the NVCA footnote's leading-tab/text run and
requires the pinned engine to accept the atomic insertion. A refusal fails the
check. RDV_NATIVE_INSERTIONS_ONLY=1 skips the replacement workload
and runs only ordinary/mixed-run insertion probes in two fresh contexts. XML
undo checks compare expanded namespace names, attribute values, and ordered
children because the package snapshot can rename equivalent namespace prefixes.
Docxodus #788 was resolved in the published 12.6.0 release. #799 extends that operation to ordinary interior insertions in 12.6.1, and #802 adds leading-tab runs in 12.6.2. Other excluded structures and disjoint drafts retain the public atomic batch to preserve neighboring formatting and one-step undo. See the upgrade notes. No native runtime patch or private editing primitive is integrated here.
The follow-up preserves Docxodus's page-flow decisions while yielding between blocks/pages and preparing incoming editable paragraphs in small chunks. The active canvas stays mounted during this work. Input, commit timers and React updates run ahead of background layout tasks; owner/version checks discard superseded layouts before handoff. Zoom changes during preparation trigger fresh measurements at the final scale.
The adapter is generated from the pinned 12.6.2 pagination implementation by
node scripts/generate-cooperative-pagination.mjs. It uses the same engine
instance and native helpers, with asynchronous traversal calls and checkpoints.
The generator verifies the upstream file's SHA-256; npm run check:api also
verifies the generated output. A dependency upgrade requires reviewing this
adapter and rerunning native page/fragment equivalence tests. There is no runtime
code generation. Attribution is in third-party-notices.md.
Page-map updates reuse previously native-validated anchor ownership only across journaled local text/run edits. Every new geometry/order/version constraint is checked again. Structural or unobserved changes, a changed renderer/mode, unknown fields, non-ASCII identifiers and table-comment presentations use full native validation. Native transactions and embedded search citations retain their native semantics. The inspector reads native XML text and list labels without triggering the full Markdown projection; native differential tests cover that text contract.
Run a production build and preview, then the interaction benchmark in another terminal:
npm run build:demo
npm run preview -- --host 127.0.0.1 --port 4191 --strictPort
# In another terminal:
npm run test:latency
RDV_BENCH_MODE=studio npm run test:latencyThe benchmark downloads/verifies the pinned NVCA fixture, or accepts
RDV_STRESS_DOCX=/path/to/NVCA.docx. It waits for the active canvas's native owner,
version and current page map, rather than treating the inert incoming pages as
ready. It exercises steady typing, caret movement, pause/resume bursts,
selected-word Bold and typing during forced reflow. Key counts, persisted text,
untouched surrounding text and browser errors are checked.
Reports and a screenshot go to test-results/latency (override with
RDV_BENCH_OUTPUT). RDV_BENCH_PROFILE=1 adds native/canvas call timings;
RDV_BENCH_CPU=1 independently adds CPU profiles. RDV_BENCH_TRACE=1 records
compressed Chrome traces per phase, including browser tasks, layout, GC, script
samples and a clock-alignment marker. It also records Long Animation Frame
attribution when supported. Traced runs are diagnostic: their instrumentation
and between-phase trace export can affect timings. The report records trace
filenames and data-loss status; lost trace data fails diagnostic validation.
Use separate output directories
for repeated runs. RDV_BENCH_DOC=sample selects the small sample, and
RDV_BENCH_URL selects a deployed production build. Run browser benchmarks
serially without concurrent builds or other CPU-heavy work.
Set RDV_BENCH_REVISION to the actual served build revision; local workspace
provenance is recorded separately and cannot establish a deployment's revision.
RDV_BENCH_EXTENDED=1 also measures explicitly formatted typing and Enter, then
checks native formatting and one-step Enter undo. It preserves those historical
phases and adds explicit run-boundary and interior insertion phases, with the
original native caret position recorded. RDV_BENCH_TARGET=late-body or
RDV_BENCH_TARGET=footnote runs the same phases in the last sufficiently long
body or footnote paragraph; the default target remains the original paragraph.
The report records the actual anchor and native text, and filenames distinguish
these additional locations.
Key-handler-to-rAF timing excludes prior input queuing and measures a paint
opportunity. Chrome Event Timing includes queuing, processing and presentation,
uses quantized durations, and is collected with a 16 ms threshold. Its observed
percentiles are not whole-population INP. Long Tasks separately measures main
thread tasks of at least 50 ms, including layout after the final keystroke.
lastEditToCurrentLayout separately records the wait for a current page map;
it includes the typing debounce and background layout work. Full repagination
can take longer than an individual input response while the canvas stays usable.
RDV_LATENCY_LIMIT_MS=150 optionally fails a run when an observed input response
exceeds that threshold. Timing is hardware/workload dependent, so normal CI
checks correctness and structural requirements rather than enforcing wall time.
useSessionQuery(controller, selector, { scope: 'document' }) opts a read into
document/settings updates only. Its default still observes the full session,
including page-map availability. The controller's shared formatting/styles reads
must be treated as read-only. Unknown mutations, raw native version gaps, session
replacement, and atomic shadow reads invalidate or bypass these caches. Enriched
editor.details.info metadata is now evaluated only when accessed and is
non-enumerable so framework prop inspection cannot trigger a native query. Hosts
should explicitly read it from the current details object when they need it.
useSessionQuery(controller, selector, { deferred: true }) lets React defer
optional preview refreshes within the same document. Values may briefly lag
edits; use current session identities and native validation for actions. Opening,
closing, or replacing the owner immediately discards the prior owner's result.
The sidebar opts its block-label catalog into this behavior while obtaining
current selectable IDs from the lightweight native inventory. Queries remain
synchronous by default, and the native editing API is unchanged.
The reference workload is the 65-page October 2025 NVCA Model Certificate of Incorporation. Its 234 body paragraphs, 110 footnote paragraphs, fields, lists, bookmarks, and section changes exercise more than a short sample document.
npm run test:performance
npm run test:stressBoth commands download and verify the same pinned fixture, or reuse
RDV_STRESS_DOCX=/path/to/document.docx. Set RDV_TEST_PORT to select the local
development server. The performance command needs Playwright Chromium; the full
integrity test also needs Python 3. Normal browser tests skip these opt-in runs.
test:performance writes NVCA-performance.json under test-results. It measures
native opening, first conversion and layout, three zoom levels, and actual typing
in two body paragraphs and a footnote. It records conversion callbacks, native
commit notifications, completed page maps, native method counts/durations, and
browser long tasks. Native method timings can overlap; do not add them together.
Typing uses a 15 ms delay per character and the editor's 350 ms commit debounce.
Opening uses a fresh browser context with cold core/worker runtimes, after the
test harness has loaded; it excludes the fixture download. The harness mounts an
editor after opening a host-owned session.
Compare runs on the same machine without other CPU-heavy work. Wall-clock values are diagnostic measurements rather than CI pass/fail thresholds. The benchmark also enforces structural performance requirements: one initial pagination, retained page DOM during zoom, bounded formatting inspections after an edit, and one native write for a contiguous typing burst. Complete page maps and preserved text remain correctness requirements. Ordinary edits must use one native block batch and zero saved-package conversions; the two body edits retain their pages, while the footnote edit repaginates from updated source HTML. The full-flow count uses the native header/footer registry parser, called once at the start of both native and cooperative pagination. That helper's duration is not a measurement of the complete asynchronous flow; layout completion events provide the end-to-end timing.
The full stress test passed before and after this change on September 12, 2026:
| NVCA stress measurement | PR #40 baseline | First pass |
|---|---|---|
| Median typing burst → native commit | 2.48 s | 1.45 s |
| Median typing burst → settled layout | 9.20 s | 6.23 s |
| Slowest of twelve edit/layout cycles | 11.51 s | 6.51 s |
| Opening, including the test's native text inventory | 19.12 s | 18.86 s |
That is a 42% reduction in median commit time and a 32% reduction in median edit-to-layout time. Opening has not materially improved in this full test. Both runs retained 65 pages, 31 native commits, 13 intentionally modified paragraphs, one added paragraph, and all integrity assertions. These local measurements include scripted typing and debounce time.
A separate matched source-harness profile measured zoom at 3.02–3.29 s before and 0.45–0.60 s after, with no pagination calls after the change. Formatting inspections during a redraw dropped from 363–364 to 10. That shorter profile's cold open improved from 13.56 s to 11.49 s; it does not perform the full stress test's initial paragraph inventory. Tracing and fixture setup differ between the profiler and Playwright's test runner, so compare each workload to itself.
- Zoom scales existing page elements and remeasures their portable page geometry. It does not reconvert, repaginate, detach the canvas, or validate every paragraph. Initial fit-to-width uses the same path. Drafts and superseded document versions cannot publish a newly measured page map from an outdated canvas.
- Canvas preparation caches native run text under each paragraph's exact native
subtree hash. A batched
getAnchorInfoslookup validates the hashes. Changed paragraphs receive fresh formatting inspection; document replacement clears the cache. Native checks before committing typing remain in place. - Contiguous insertions and deletions stay single native edits. Word-level diffing remains available for drafts that contain multiple changes, preserving the formatting of unchanged words without turning a simple insertion into a batch.
npm run test:performancemakes these costs and regressions reproducible.
The full NVCA integrity suite verifies the saved document separately, including unchanged paragraph XML, fields, bookmarks, notes, sections, and unrelated package parts. See the stress-test details.
React now shares one native session handle between its complete editing API and
Docxodus 12.4.1's ListAnchors and RenderEditorBlocksHtml bridge. It does not
instantiate a second upstream editor or save/reopen the document to render a
typing burst. A bounded journal follows successful text/character-formatting
mutations, including synchronous nested batches. Unknown changes, rollbacks,
missing history, and owner replacement cannot be published as local block edits.
The viewer retains authoritative unpaginated HTML, including hidden footnote and endnote registries. Native block updates preserve pagination metadata and the document's note reference ordinals. For unfragmented body paragraphs, geometry is compared with the last committed layout, before browser typing changed the DOM. Unchanged geometry retains page elements and the canvas event handlers; the page map is measured for the new native version. Changed wrapping, fragments, tables, and notes repaginate the updated source. Structural/global edits, image-bearing blocks, nested source identities, and unsupported custom render profiles retain the full converter fallback.
Editor-owned sessions and demo sessions also use emitMarkdownPatch: false, as
the native TypeScript editor does. General host-owned controllers retain the
upstream default for consumers that need Markdown patches. The performance
benchmark explicitly opts out; the full integrity stress test continues to
exercise the general controller default. The studio no longer saves snapshots on
every notification: it requests them when Verify or Export is open.
The first live-block benchmark on September 12, 2026 measured:
| Same NVCA benchmark | Previous pass | Native blocks |
|---|---|---|
| First body typing → settled layout | 5.43 s | 1.71 s |
| Middle body typing → settled layout | 5.36 s | 1.80 s |
| Footnote typing → settled layout | 5.36 s | 2.55 s |
| Native write duration | 148–158 ms | 8–49 ms |
| Saves / whole conversions per ordinary edit | 1 / 1 | 0 / 0 |
| Pagination calls per body edit | 1 | 0 |
These timings include scripted typing and the 350 ms debounce. The new profile's Markdown setting contributes to the native write improvement. Body commit → settled geometry was about 0.51–0.52 s; footnote reflow took 1.39 s after commit. Cold open remains a full conversion and layout, and is a separate performance problem. The native block render itself measured 9–102 ms for these paragraphs.
The full NVCA integrity workload also passed with the host controller's original Markdown-patch setting. Its median typing → settled layout fell from 6.23 s to 3.53 s (43% faster); median typing → commit was 1.29 s and the slowest edit was 4.92 s. It retained 65 pages, 31 commits, 13 intentional paragraph changes, one added paragraph, and all independent XML/package assertions. That run's cold opening plus complete native text inventory took 20.62 s, versus 18.86 s in the previous pass; this change does not claim a cold-open improvement.
After the paragraph-presentation fix, a final repeat passed all integrity checks with a 2.59 s median typing → settled layout. Its body benchmark cycles were 1.79 / 1.78 s and its footnote cycle was 2.51 s, with the same zero-save, zero-conversion guards. Timings vary with the local run; the count-based guards and document integrity assertions are the portable regression requirements.
- Repaginate the affected story/section, then downstream pages until layout stabilizes. Preserve footnote placement, paragraph fragments, focus, and exact versioned page-map completeness. Avoid substituting stale geometry for a fresh layout.
- Reduce cold opening and main-thread work through runtime startup overlap, demand-driven text validation, and bounded scheduling. Measure time to the first editable page separately from the time to a complete document layout.
The current implementation updates blocks incrementally and can retain an unchanged page layout. It does not yet paginate only a subset of changed pages.