Preview of main at d0a501a, 2026-11-07

webcpp::cobalt makes Boost.Cobalt-style C++20 applications usable in browsers through Emscripten and in WASIp2/P3 runtimes such as Wasmtime. JSPI and Asyncify are Emscripten suspension variants; they are not WASI versions. Cobalt supplies coroutines and asynchronous composition, while Asio supplies the executor and I/O.

Start with Tutorial: await a timer to await a timer. Use How-to: select the compiled integration to select the runner and optional TLS, Configuration and deployment profiles to choose requirements, and Differences to understand the boundaries of compatibility. The Feature matrix distinguishes target facilities from runtime permission.

Tutorial: await a timer

Use the library at libs/cobalt in the WebCPP superproject, matching Boost 1.92 headers and a configured C++20 compiler. The application writes co_main; the separately linked runner owns main and drives its executor.

#include <webcpp/test/exit_status.hpp>

#include <webcpp/asio/steady_timer.hpp>
#include <webcpp/cobalt/main.hpp>
#include <webcpp/cobalt/op.hpp>
#include <webcpp/cobalt/result.hpp>
#include <webcpp/cobalt/this_coro.hpp>

#include <chrono>
#include <cstdio>

// Boost 1.92 intentionally omits this promise hook without exceptions. Clang
// 21 and 23 still warn at the coroutine definition even with -fno-exceptions.
// Keep the workaround on this native example, without changing Boost's types.
#if defined(__clang__) && defined(WEBCPP_TARGET_NATIVE) && !defined(__EXCEPTIONS)
#if __has_warning("-Wcoroutine-missing-unhandled-exception")
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wcoroutine-missing-unhandled-exception"
#endif
#endif

webcpp::cobalt::main co_main([[maybe_unused]] int argc, [[maybe_unused]] char** argv) {
    // Cobalt's awaiter has static members called by the compiler's co_await expansion.
    // NOLINTNEXTLINE(readability-static-accessed-through-instance)
    const auto exec = co_await webcpp::cobalt::this_coro::executor;
    webcpp::asio::steady_timer timer(exec, std::chrono::milliseconds(50));
    auto [error] = co_await webcpp::cobalt::as_tuple(timer.async_wait(webcpp::cobalt::use_op));
    if (error) {
        std::printf("timer error: %d\n", error.value());
        co_return webcpp::test::exit_status(1);
    }
    std::puts("cobalt slept");
    co_return webcpp::test::exit_status(0);
}

#if defined(__clang__) && defined(WEBCPP_TARGET_NATIVE) && !defined(__EXCEPTIONS)
#if __has_warning("-Wcoroutine-missing-unhandled-exception")
#pragma clang diagnostic pop
#endif
#endif

The example’s webcpp::test::exit_status reports its result to the project’s browser test harness. It is test support, not a Cobalt API requirement. The coroutine gets its executor, awaits an Asio timer with Cobalt’s completion token, checks the error, then returns its exit status.

From the superproject root:

unset CPATH CPLUS_INCLUDE_PATH C_INCLUDE_PATH
b2 -a variant=release libs/cobalt/example//asio_cobalt.output

The matched output is:

cobalt slept

For a real browser, build the page driver with Emscripten:

b2 -a toolset=emscripten variant=release libs/cobalt/test/browser//browser-pages
b2 -a toolset=emscripten variant=release webcpp-suspend=asyncify libs/cobalt/test/browser//browser-pages

The driver serves the example page and checks its interaction in Chrome. A successful Node run alone does not establish browser support.

How-to: select the compiled integration

Include webcpp/cobalt/main.hpp and the operation headers and use webcpp::cobalt. Select one entry-point model:

B2 dependency Application contract

/webcpp/cobalt//core

The application supplies main and drives its context.

/webcpp/cobalt//cobalt

The application supplies co_main; link exactly one runner.

/webcpp/cobalt//io_ssl

Add the corrected SSL wrapper to a custom-main application.

/webcpp/cobalt//cobalt_ssl

Combine the runner and corrected SSL wrapper.

The SSL targets select the same source-built OpenSSL and embedded CA provider as Asio and Beast. The plain core does not pull in TLS. Browser HTTPS/WSS uses the browser’s TLS implementation and trust policy, not these OpenSSL targets.

Build with another build system

sources.json is the source inventory, split into core, runner, ssl and multi_add for each target. B2’s generated src/sources.jam comes from the same inventory. Consumers compile these already shipped files; the maintainer-only upstream/sync.py is not a build step.

Use matching Boost 1.92 headers. Compile sources and application with the same target, exception mode, threading ABI and Cobalt configuration. For native, define BOOST_COBALT_NO_LIB=1 when linking the explicit archives. The native core and runner use the unchanged upstream sources. The native SSL inventory selects WebCPP’s separate corrected wrapper and composed-transfer adapter.

Add Asio’s explicit runtime source for Wasm: src/wasip2/pollable.cpp, src/wasip3/waitable.cpp or src/browser_src.cpp from the Asio library. Verify the pinned WASI SDK ABI before compiling its bridge. Emscripten also requires embind, stack exports and the chosen suspension flags. Its browser bridge must reach the final link as an object, so JavaScript import metadata is retained.

For guest TLS, provide matching OpenSSL headers and libssl/libcrypto, the generated embedded-CA header include directory, WEBCPP_ASIO_HAS_OPENSSL=1 and WEBCPP_COBALT_LINK_SSL=1. A macro alone does not link or configure OpenSSL. The WASI OpenSSL provider also links wasi-libc’s wasi-emulated-getpid, wasi-emulated-signal, wasi-emulated-process-clocks and wasi-emulated-mman support libraries, after its crypto archive, as the consumer recipe records. Replacing the CA bytes is an Asio TLS-context operation; it does not change the browser’s certificate store.

The superproject’s tools/test/fixtures/portable-network/CMakeLists.txt is a consumer recipe. tools/test/portable_network_distribution.py creates a source archive with a SHA-256 inventory, deletes its staging inputs and extracts it into a path with spaces. The archive omits Git/B2/cache files. Consumers use a direct compiler or CMake. Compiler dependency files verify the actual source and header paths, the complete Cobalt source selection and the configuration of each source. Checkout headers and undeclared external dependencies fail that audit.

The optional --openssl-prefix and --ca-header inputs copy explicitly supplied dependencies into the extracted tree before compiling the TLS tests. They must match the selected target and ABI. --evidence-dir <directory> preserves the tested source archive and compiler-receipt.json, including commands and resolved dependency paths. These are local consumer proofs, not a second release pipeline.

For example, run the native CMake consumer from the superproject:

python3 tools/test/portable_network_distribution.py \
  --compiler /path/to/clang++ --boost-include /path/to/boost/include \
  --target native --build-system cmake \
  --cobalt-executor custom --cobalt-pmr custom \
  --evidence-dir /path/to/evidence

The custom configuration is the compiled fixture test/distribution/consumer_config.hpp. It declares an Asio context executor and a counting PMR resource before any Cobalt header. Every compiled source receives that same preincluded header. The test crosses translation-unit boundaries and checks allocations through the compiled core’s allocator. It proves that concrete customization, not every user-defined executor or memory implementation.

Await a browser Promise

Use Asio’s browser::async_await with the executor obtained from this_coro::executor and Cobalt’s use_op completion token. The operation resumes the coroutine when JavaScript settles the Promise; rejection follows the bridge’s error contract. DOM-event waits use the corresponding Asio bridge. Neither operation exists on a native or WASI target without JavaScript hosting. The Promise tests cover both exception modes and both Emscripten suspension modes.

Preserve the corrected native SSL composition

Include webcpp/cobalt/io/ssl.hpp, keep the concrete io::ssl::stream type and call webcpp::cobalt::io::read or write for complete-buffer transfers. These overloads preserve cancellation through Asio’s composed operations. read_some and write_some remain primitive operations on the corrected stream.

Do not erase the stream to Boost’s generic I/O interface and expect this composition correction to follow it. That selects Boost’s original generic read/write implementation, whose cancellation association failed the native regression. The wrapper’s handshake state protections still apply, but this does not repair an upstream composition chosen through a different static type.

Stream and buffer storage must outlive the pending operation. A transferred-byte count can be nonzero on cancellation. Terminal cancellation does not make a connection reusable; end that connection according to the underlying Asio contract.

SSL handshake and stream state

The wrapper fixes the Boost.Cobalt SSL state defects on native and WASIp2/P3. The same state guards apply with exceptions enabled or disabled in a supported compiler/threading profile. WASI SDK 34 provides both exception modes for single-thread P2/P3 and only EH off for cooperative P3; native co_main limitations remain as described in Exceptions and errors. Browser HTTPS/WSS uses host TLS and does not use this wrapper.

The fixed wrapper supports STARTTLS. Before its first handshake, reads and writes use plain TCP. Complete a successful, verified handshake before sending confidential application data. secure() reports TLS establishment, not whether the application configured trust and hostname verification.

State or operation Behavior

Before the first handshake

secure() is false; plain TCP I/O is allowed.

Successful handshake

secure() becomes true before the coroutine resumes; application I/O uses TLS.

Failed or cancelled handshake

secure() stays false; further application I/O returns not_connected with zero bytes.

Handshake after an attempt has started

Returns already_started; use a new stream for another attempt.

Shutdown before TLS establishment

Returns no_protocol_option.

Completed shutdown, including failure or cancellation

Clears secure() and blocks application I/O; another shutdown returns no_protocol_option.

Both handshake overloads update the same state. The buffered overload reports consumption of already-read handshake bytes. Serialize state-changing operations; the wrapper does not synchronize overlapping handshakes, shutdown or direct SSL object manipulation.

native_ssl_handle() returns a borrowed SSL*, owned by the stream. Do not free it or retain it after stream destruction. Use it to configure SNI before the handshake and check the result. native_handle() still denotes the TCP socket. Peer trust, hostname verification and SNI remain distinct application duties.

Cancelling an application transfer cannot retract bytes already sent and does not undo the handshake, so secure() may remain true after transfer cancellation. It is not a connection-health or retry-safety indicator. End the connection after terminal cancellation; do not infer safe reuse from that flag.

Configuration and deployment profiles

This source distribution requires Boost 1.92.0 headers. The public configuration rejects other Boost versions before an application can combine them with the pinned compiled sources, including when compiling without B2. The native core inventory includes src/native_version.cpp for the same check when only the archive is built. Do not omit source-inventory entries.

Define requirements before any Cobalt header, consistently in every translation unit. WEBCPP_COBALT_HAS_* macros are read-only observations: defining one does not supply the missing environment feature. REQUIRE_* controls default to unset; setting one to 1 requests a compile-time diagnostic when unavailable.

Control or observation Meaning

WEBCPP_COBALT_NO_EXCEPTIONS

Derived from the collection’s exception policy, or explicitly selected for this integration. It does not change the compiler’s exception ABI or repair upstream issue 287.

WEBCPP_COBALT_LINK_SSL

Unset by default; set to 1 when explicitly linking the matching corrected SSL implementation and provider; supplied by the SSL B2 targets.

WEBCPP_COBALT_REQUIRE_SOCKET_BACKEND

Require guest TCP/UDP, unavailable in a normal browser.

WEBCPP_COBALT_REQUIRE_OPENSSL

Require both a guest TLS target and explicit SSL linkage.

WEBCPP_COBALT_REQUIRE_THREADS

Require a thread-enabled Asio/compiler profile.

WEBCPP_COBALT_REQUIRE_LOCAL_SOCKETS

Require native local sockets.

WEBCPP_COBALT_REQUIRE_SIGNALS

Require native operating-system signals, not coroutine cancellation signals.

WEBCPP_COBALT_REQUIRE_SERIAL_PORT

Require native serial-port support.

WEBCPP_COBALT_REQUIRE_REVERSE_DNS

Require reverse name lookup, unavailable in the WASI/browser adapters.

WEBCPP_COBALT_REQUIRE_PIPE_CREATION

Require guest-created asynchronous pipes with transfer, cancellation and EOF support. WASIp2 has no guest pipe creation; the Emscripten lifecycle is not supported.

WEBCPP_COBALT_REQUIRE_POSIX_STDIO

Require native POSIX descriptors for asynchronous stdio. SDK 34’s WASI stdio descriptors do not provide nonblocking mode.

WEBCPP_COBALT_REQUIRE_POLLABLE_STDIO

Require Asio’s explicit WASIp2 pollable stdio adapter, usable with Cobalt’s completion tokens.

WEBCPP_ASIO_DEFAULT_MAX_HANDLERS_PER_TURN

Asio’s shared browser scheduling default, 100; compile the runner with the same value. It is a handler-count budget, not a time limit.

The corresponding HAS_SOCKET_BACKEND, HAS_OPENSSL_BACKEND, HAS_THREADS, HAS_LOCAL_SOCKETS, HAS_SIGNALS, HAS_SERIAL_PORT and HAS_REVERSE_DNS observations use the WEBCPP_COBALT_ prefix. HAS_BROWSER_BRIDGE, HAS_BROWSER_WORKERS and HAS_HOST_DNS distinguish JavaScript integration, pthread hosting and forward lookup. Internal BACKEND_* macros are not public configuration controls.

In a browser build, including io.hpp, io/acceptor.hpp, io/socket.hpp, io/stream_socket.hpp or io/datagram_socket.hpp requests a raw socket facility and produces a targeted diagnostic. Include only the coroutine headers needed by a browser HTTP/WebSocket client and use Beast’s host transport adapter. The same socket headers select the guest transport on native and WASIp2/P3.

Keep Boost’s build-wide Cobalt controls when selecting executor and memory policies: BOOST_COBALT_USE_IO_CONTEXT, BOOST_COBALT_CUSTOM_EXECUTOR, BOOST_COBALT_USE_STD_PMR, BOOST_COBALT_USE_BOOST_CONTAINER_PMR, BOOST_COBALT_USE_CUSTOM_PMR and BOOST_COBALT_NO_PMR. Native sources read them directly; Wasm configuration forwards them to the shipped implementation. The defaults are the type-erased Asio executor and standard-library PMR. Choose one executor policy and one PMR policy. Rebuild the complete core, runner, optional SSL and application with matching definitions; changing only one translation unit violates the library’s configuration contract.

Custom executor and PMR declarations follow Boost’s customization convention: supply boost::cobalt::executor or boost::cobalt::pmr in a configuration header included before Cobalt in every source. For Wasm, the executor must belong to the selected WebCPP Asio backend. A custom PMR implementation or Boost.Container PMR also brings its own explicit dependencies. Source-archive consumers cover the default policy, io_context plus no-PMR, and an application-declared context executor with counting PMR, using direct compilation and CMake. These witnesses do not certify arbitrary custom executor/resource implementations.

Conflicting executor or PMR selections in one translation unit produce a configuration error. There is no general linker guard for arbitrary configuration differences between separately compiled translation units or prebuilt archives. The consumer recipe applies one common configuration target to the application, core, runner and SSL. Its dependency audit rejects a compiled source missing the requested policy. Rebuild all of them when changing policy; an existing archive cannot acquire a different ABI just by defining a macro in the application.

HAS_PIPE_CREATION, HAS_POSIX_STDIO and HAS_POLLABLE_STDIO are separate observations. Receiving a host-provided stream does not imply that the guest can create a pipe. Use WEBCPP_COBALT_FOR from async_for.hpp for asynchronous range iteration; it forwards to the selected coroutine backend.

Emscripten 6.0.11 does not provide the complete pipe lifecycle. A Node test confirms byte transfer and pending-read cancellation through Cobalt. A separate pipe_eof_sdk_limitation probe calls only libc: after closing the last writer, poll reports POLLIN|POLLHUP, but an empty nonblocking read returns EAGAIN instead of EOF. This SDK limitation leaves HAS_PIPE_CREATION at zero; the passing negative probe is not lifecycle support or browser evidence. The probe fails if the SDK behavior changes, requiring the capability to be re-evaluated. Native and WASIp3 continue to test closure of the final writer through Cobalt. Native Windows retains Boost.Asio’s broken_pipe error for that read; native POSIX and WASIp3 report eof. In each case no further bytes are returned.

Feature matrix

This table describes facilities, not a claim that every upstream example has passed in every combination. See Testing for the current evidence gates.

Facility Native WASIp2 WASIp3 Emscripten

Core coroutines and Asio timers

Boost core

Shipped backend

Shipped backend

Shipped backend

TCP/UDP and forward DNS

Operating system

Pollables; host grants

Waitables; host grants

No raw guest transport

Corrected Cobalt SSL wrapper

OpenSSL

OpenSSL

OpenSSL

Browser-managed TLS instead

Promises and DOM events

Not applicable

Not applicable

Not applicable

Asio browser bridge

Single-thread profile

Available

Available

Available

JSPI or Asyncify

Thread profile

Native threads

Unavailable in SDK 34

Experimental cooperative threads, EH off

Pthreads; isolation and worker hosting required

C++ exceptions

On/off

On/off, single-thread

On/off single-thread; off for cooperative profile

On/off; flags depend on JSPI/Asyncify

OS signals, local sockets, serial ports

Subject to native Boost/platform

Unavailable

Unavailable

Unavailable

Reverse DNS

Native resolver

Unavailable

Unavailable

Unavailable

Guest asynchronous pipe pair

Subject to native Boost/platform

Unavailable

Available

Unsupported lifecycle

Async stdio through POSIX descriptors

Native POSIX only

No nonblocking mode

No nonblocking mode

Use an explicit browser channel

Explicit pollable stdio adapter

Not applicable

Cancellation and reuse supported

Not implemented

Not applicable

WASIp3 cooperative threads do not run simultaneously on CPU cores. Browser pthreads require the hosting policy and shared-memory facilities established by the worker examples. Neither a macro nor a compiled binary grants network access. The runtime can deny sockets or DNS even when the target provides them.

Exceptions and errors

Both exception modes remain selectable. The build warns about Boost.Cobalt issue 287: moving some pending coroutine objects with libc++ and exceptions disabled can abort. This is an upstream limitation, not a claim that every use of std::move fails. The warning is informational; it does not enable exceptions or make the operation safe. Use the versioned reproducer when evaluating another compiler/runtime. The native runtime tests keep Apple Clang’s known missing-promise-member diagnostic visible with -Wno-error=coroutine-missing-unhandled-exception for their no-exceptions consumers. This test-local setting is not exported by the library targets; external strict builds must account for the upstream diagnostic described in Differences.

Native MSVC rejects co_main with exceptions disabled because Boost 1.92’s main_promise omits unhandled_exception. The test suite classifies that specific configuration as an upstream compile limitation, paired with the same coroutine compiling with exceptions enabled and a no-exceptions witness for the missing promise member. This does not disable other no-exceptions consumers or change the native Boost type. Use exceptions for native MSVC co_main applications.

Testing

The migration remains under local validation. The current Original applications and environment counterparts records each original application and its available counterparts against the shipped implementation. Historical Asio/Cobalt results do not certify the new source layout. The independent whole-candidate review and its correction reviews accompany the local lint gate. Remote CI has separate evidence; a local review is not a remote CI verdict.

Native identity preserves Boost 1.92 defects outside the corrected SSL wrapper. The upstream-limitations lane records precise failures for composed accept and composition cancellation. Its output says UPSTREAM-LIMITATION; a passing negative probe means the limitation was reproduced, not that cancellation works. An unexpected exit, diagnostic or newly fixed upstream behavior fails the probe and requires the compatibility record to be revisited.

The finite echo counterpart uses accept(socket&), which forwards cancellation directly to the pending accept. It avoids Boost 1.92’s composed accept limitation without changing native types or sources. Its TCP driver checks concurrent traffic, EOF, cancellation before any connection, cancellation with a live session, peer reset after a confirmed echo and invalid arguments. Both cancellation cases require the server to finish normally and report its exact session and byte counts.

The affected owned coroutine tests scope GCC 14’s allocation false-positive diagnostic to their coroutine functions. The immutable upstream HTTP and ticker compile probes instead keep that warning visible with -Wno-error=mismatched-new-delete, only for their GCC 14 targets. Other warnings remain errors, and neither setting is a library usage requirement. See Differences for the upstream explanation.

The immutable upstream ticker declares a local msg that shadows its msg parameter. MSVC diagnoses that valid source with C4457 under /W4; /WX then rejects the compile probe. Only original_ticker selects /wd4457 on MSVC. The source remains byte-identical, other warnings remain errors, and this option is not exported to library consumers or other test programs. That same MSVC probe uses /bigobj: its template-heavy Debug translation unit exceeds the default COFF section limit (C1128). This changes the object-file format limit, not the source, runtime behavior or warning policy.

The tests distinguish immutable upstream programs, namespace-only migrations and behavioral counterparts. test/applications/upstream retains original hashes; test/applications/prepare.py produces the separately identified namespace migrations. A missing host facility is documented or diagnosed, never replaced by an empty successful program.

The spsc-wakeup lane checks only the await_ready/await_suspend lost-wakeup window. The adaptation closes that window but retains the original queue’s delayed-notification race: a notification can resume a writer after its free slot has already been reused, and a failed push is ignored. The spsc-sequence lane is a deterministic limitation probe, with the immutable original on native and the unchanged counterpart on native, Emscripten and WASIp3. Passing means the known value loss was reproduced, not that concurrent transfer is reliable. The browser workbench marks SPSC unavailable and does not start it. A native failure in the original does not establish support for a Wasm backend.

Native SSL has compile-time type-identity tests for both header orders, plus runtime client, handshake-state, transfer-cancellation and shutdown tests against real local peers. The same TLS 1.2/1.3 state tests run on WASIp2/P3. A native CMake consumer also compiles the complete source inventory and runs those tests from a copied source snapshot without B2, Git or replacement Boost headers.

The Cobalt-owned tls-integration lane runs the SSL client, state and cancellation fixtures in native single/multi-thread profiles with exceptions on/off, WASIp3 single-thread profiles with exceptions on/off, and WASIp3 cooperative threads with exceptions off. It reuses the shared real TLS peer driver and builds each Cobalt source directly, keeping the test report under Cobalt ownership. Native MSVC single-thread fixtures select the static CRT so the provider uses its no-threads configuration. The existing tls lane retains its native, WASIp2 and WASIp3 coverage.

The SSL client also checks move construction, socket identity and cancellation after destroying the source, both before and after handshake completion.

Browser examples keep cancellation state in the owning module instance, with a scoped C++ registration. Duplicate registration cannot replace an active run; normal completion and exception unwinding remove it. Browser tests also call the exported cancellation function after completion and require a zero result.

The state cases cover STARTTLS, a buffered ClientHello, state observed at await time, trust rejection, malformed CA data, hostname verification and SNI. Transfer cancellation covers primitive reads/writes and complete-buffer operations with partial progress. The peer applies backpressure; only an actual operation_aborted satisfies a cancellation case. A completion that wins the race requires a fresh connection and a bounded retry, rather than being counted as cancellation. An outer watchdog catches lost completion.

Shutdown tests first wait until the peer observes close_notify. The peer then either closes without its own TLS shutdown, producing stream_truncated, or holds the connection while the coroutine requests cancellation, producing operation_aborted. Both cases must clear secure(), block application I/O and reject a second shutdown. Elapsed time alone is not proof of a pending operation.

b2 -a variant=release libs/cobalt/test/tls//tls
b2 -a libs/cobalt/test/tls//tls-integration
b2 -a toolset=clang-wasip3 libs/cobalt/test/tls//tls-integration
b2 -a variant=release libs/cobalt/test/tls//native_ssl_identity libs/cobalt/test/tls//native_ssl_identity_boost_first
b2 -a toolset=clang-wasip2 variant=release libs/cobalt/test/applications//migrated-portable
b2 -a toolset=clang-wasip3 variant=release libs/cobalt/test/applications//migrated-portable-p3

The TLS drivers grant networking explicitly and create short-lived local certificates. Run them with a Python/OpenSSL installation supporting TLS 1.3. The browser lanes use real Chrome and check page output and worker completion; Node-only examples are labeled separately. The shared published test report is the WebCPP report; it is evidence for the commit it names, not for an unsubmitted local candidate.

The worker lifecycle test receives a posted readiness notification after the worker has started its asynchronous timer wait. It then cancels and awaits the worker, checking completion and executor affinity. Readiness changes a timer’s expiry on the creator’s executor, so a notification arriving before the wait is retained. The test avoids repeated one-millisecond readiness polling, which overloaded the browser under controlled CPU throttling. Its five-second deadline still bounds the test; it is not a general worker-latency guarantee or a change to the SDK’s timer polling.

Performance, memory and binary-size comparisons must use optimized builds and record source hashes, compiler/linker flags, EH, threads, suspension mode and runtime. Raw Wasm and JavaScript sizes are separate artifacts. An unavailable measurement is not zero. The Release measurements of the shipped implementation records fresh observations of the shipped implementation, with source and artifact identities. Prior Asio benchmark results retain their original dates and environments.

bench/results/2026-11-07/ retains the quantitative report and raw archive. test/applications/results/2026-11-07/ separately retains the three libraries’ application matrices, commands, logs and source snapshots. Each archive has a SHA-256 file. These local results do not stand in for CI of the coordinated commits. The independent review and local closure evidence are recorded separately in the superproject’s execution ledger.

Original applications and environment counterparts

The inventory pins all twelve Cobalt 1.92 applications. Native core types are Boost types; Wasm uses the shipped WebCPP backend. Every cell below names the actual target, thread/exception setting and host. Browser page and dedicated worker observations are separate from Node.

A controlled network counterpart changes endpoints, ports and certificate setup. It retains the application protocol. Infinite original servers are stopped after observed traffic; that does not prove graceful shutdown. Browser HTTP/WSS counterparts use host transports and do not provide raw TCP listeners.

Original examples run in Release, so an original assert may be disabled by NDEBUG. A normal exit is not evidence for an assertion that did not execute. Separate finite portable counterparts check values, cancellation and completion explicitly in the same feasible profiles.

Current support includes the SPSC delayed-notification limitation: both the original queue and its wakeup adaptation can lose values. Their deterministic limitation probes preserve queue behavior; the browser workbench disables the counterpart. Earlier dated successful observations remain historical and do not establish reliable concurrent transfer.

source-requires-exceptions means the original application contains exception syntax. It does not mean Cobalt itself requires exceptions. Native no-EH Clang builds retain the documented upstream promise warning; only that diagnostic is nonfatal in these test consumers. P3 multi means cooperative threads, not CPU parallelism.

native

Profile channel delay delay_op echo_server http outcome python signals spsc thread thread_pool ticker

native-single-on-native

pass

pass

pass

fixture

fixture

pass

upstream defect + counterpart

pass

upstream defect + counterpart unavailable

pass

pass

fixture

native-single-off-native

pass

pass

pass

source EH

fixture

pass

source EH

pass

upstream defect + counterpart unavailable

source EH

source EH

source EH

native-multi-on-native

pass

pass

pass

fixture

fixture

pass

upstream defect + counterpart

pass

upstream defect + counterpart unavailable

pass

pass

fixture

native-multi-off-native

pass

pass

pass

source EH

fixture

pass

source EH

pass

upstream defect + counterpart unavailable

source EH

source EH

source EH

wasip2

Profile channel delay delay_op echo_server http outcome python signals spsc thread thread_pool ticker

wasip2-single-on-wasmtime

pass

pass

pass

fixture

fixture

pass

dependency

pass

threads

threads

threads

fixture

wasip2-single-off-wasmtime

pass

pass

pass

source EH

fixture

pass

dependency

pass

threads

source EH

source EH

source EH

wasip2-multi-on-wasmtime

SDK

SDK

SDK

SDK

SDK

SDK

SDK

SDK

SDK

SDK

SDK

SDK

wasip2-multi-off-wasmtime

SDK

SDK

SDK

SDK

SDK

SDK

SDK

SDK

SDK

SDK

SDK

SDK

wasip3

Profile channel delay delay_op echo_server http outcome python signals spsc thread thread_pool ticker

wasip3-single-on-wasmtime

pass

pass

pass

fixture

fixture

pass

dependency

pass

threads

threads

threads

fixture

wasip3-single-off-wasmtime

pass

pass

pass

source EH

fixture

pass

dependency

pass

threads

source EH

source EH

source EH

wasip3-multi-on-wasmtime

SDK

SDK

SDK

SDK

SDK

SDK

SDK

SDK

SDK

SDK

SDK

SDK

wasip3-multi-off-wasmtime

pass

pass

pass

source EH

fixture

pass

dependency

pass

upstream defect + counterpart unavailable

source EH

source EH

source EH

jspi

Profile channel delay delay_op echo_server http outcome python signals spsc thread thread_pool ticker

jspi-single-on-node

pass

pass

pass

platform

platform

pass

dependency

pass

threads

threads

threads

platform

jspi-single-on-page

pass

pass

pass

platform

platform + counterpart

pass

dependency

pass

threads

threads

threads

platform + counterpart

jspi-single-on-worker

pass

pass

pass

platform

platform + counterpart

pass

dependency

pass

threads

threads

threads

platform + counterpart

jspi-single-off-node

pass

pass

pass

platform

platform

pass

dependency

pass

threads

source EH

source EH

platform

jspi-single-off-page

pass

pass

pass

platform

platform + counterpart

pass

dependency

pass

threads

source EH

source EH

platform + counterpart

jspi-single-off-worker

pass

pass

pass

platform

platform + counterpart

pass

dependency

pass

threads

source EH

source EH

platform + counterpart

jspi-multi-on-node

pass

pass

pass

platform

platform

pass

dependency

pass

upstream defect + counterpart unavailable

pass

pass

platform

jspi-multi-on-page

pass

pass

pass

platform

platform + counterpart

pass

dependency

pass

upstream defect + counterpart unavailable

pass

pass

platform + counterpart

jspi-multi-on-worker

pass

pass

pass

platform

platform + counterpart

pass

dependency

pass

upstream defect + counterpart unavailable

pass

pass

platform + counterpart

jspi-multi-off-node

pass

pass

pass

platform

platform

pass

dependency

pass

upstream defect + counterpart unavailable

source EH

source EH

platform

jspi-multi-off-page

pass

pass

pass

platform

platform + counterpart

pass

dependency

pass

upstream defect + counterpart unavailable

source EH

source EH

platform + counterpart

jspi-multi-off-worker

pass

pass

pass

platform

platform + counterpart

pass

dependency

pass

upstream defect + counterpart unavailable

source EH

source EH

platform + counterpart

asyncify

Profile channel delay delay_op echo_server http outcome python signals spsc thread thread_pool ticker

asyncify-single-on-node

pass

pass

pass

platform

platform

pass

dependency

pass

threads

threads

threads

platform

asyncify-single-on-page

pass

pass

pass

platform

platform + counterpart

pass

dependency

pass

threads

threads

threads

platform + counterpart

asyncify-single-on-worker

pass

pass

pass

platform

platform + counterpart

pass

dependency

pass

threads

threads

threads

platform + counterpart

asyncify-single-off-node

pass

pass

pass

platform

platform

pass

dependency

pass

threads

source EH

source EH

platform

asyncify-single-off-page

pass

pass

pass

platform

platform + counterpart

pass

dependency

pass

threads

source EH

source EH

platform + counterpart

asyncify-single-off-worker

pass

pass

pass

platform

platform + counterpart

pass

dependency

pass

threads

source EH

source EH

platform + counterpart

asyncify-multi-on-node

pass

pass

pass

platform

platform

pass

dependency

pass

upstream defect + counterpart unavailable

pass

pass

platform

asyncify-multi-on-page

pass

pass

pass

platform

platform + counterpart

pass

dependency

pass

upstream defect + counterpart unavailable

pass

pass

platform + counterpart

asyncify-multi-on-worker

pass

pass

pass

platform

platform + counterpart

pass

dependency

pass

upstream defect + counterpart unavailable

pass

pass

platform + counterpart

asyncify-multi-off-node

pass

pass

pass

platform

platform

pass

dependency

pass

upstream defect + counterpart unavailable

source EH

source EH

platform

asyncify-multi-off-page

pass

pass

pass

platform

platform + counterpart

pass

dependency

pass

upstream defect + counterpart unavailable

source EH

source EH

platform + counterpart

asyncify-multi-off-worker

pass

pass

pass

platform

platform + counterpart

pass

dependency

pass

upstream defect + counterpart unavailable

source EH

source EH

platform + counterpart

Evidence boundaries

  • pass: the original or namespace-only migrated program ran and completed.

  • fixture: a controlled endpoint adaptation ran against real TCP/TLS peers.

  • SDK, platform, threads, dependency: the exact prerequisite is absent in that profile.

  • source EH: explicit exception syntax in the example is rejected with exceptions disabled.

  • upstream defect: the original failure has its own evidence; counterpart status remains separate. counterpart unavailable preserves a limitation inherited by the adaptation.

Raw JSON cells retain source hashes, implementation snapshots, commands and evidence filenames. The native Python extension is an optional CPython 3.14/nanobind experiment, not a Wasm capability. The five upstream benchmark sources remain inventoried and compile-probed; current performance uses separately identified finite matched workloads.

Pinned upstream benchmark sources

All five benchmark sources are compiled with the measured profiles and strict diagnostics. These are compile probes, not performance results. The original sources remain unchanged; Wasm variants change namespaces/includes and make the original concurrency-hint macro include explicit.

Source Observed source constraints

channel

The original printf format does not match chrono::duration::rep under strict format warnings.

immediate

The original printf format does not match chrono::duration::rep under strict format warnings.

monotonic

The original names asio::cobalt_compose, absent in the pinned Asio interface. The original printf format does not match chrono::duration::rep under strict format warnings.

parallel

The original contains throw syntax in a no-EH profile. The original printf format does not match chrono::duration::rep under strict format warnings.

post

The original printf format does not match chrono::duration::rep under strict format warnings.

Release measurements of the shipped implementation

These local measurements compare Boost-backed native interfaces with the shipped Wasm implementation on one machine. They are not a cross-machine performance guarantee. See the raw environment, commands, hashes and samples accompanying the tables.

Sizes cover -O2, -O3, -Os and -Oz, each with full LTO off/on. Runtime comparisons use -O3 without LTO across every feasible profile. All builds use Release and NDEBUG. EH-on uses -fwasm-exceptions for JSPI/WASI and -fexceptions for Asyncify in this toolchain. Those comparisons include the selected exception code generation, not suspension alone. The workload executable contains seven finite matched workloads, not an unchanged upstream application. The baseline contains only an empty runner. Browser payload is JavaScript plus Wasm; native is a Mach-O executable. Runtime installations and native system shared libraries are outside these payload sizes.

All 136 optimization/profile builds also execute the empty runner and seven short checked workloads for both libraries: 2,176 payload qualification runs in native, Node or Wasmtime. They validate the size artifacts; their timings are excluded from the performance tables. Real-browser measurements and correctness observations below remain separate.

Single/multi are B2 threading properties. Native single does not disable Boost threads; Wasm multi selects the thread-capable SDK profile. Each workload runs one context on one execution thread. This is not a multicore throughput comparison. P3 threads are cooperative.

Build time is one forced rebuild of six programs per setting with three compiler jobs and a warmed SDK cache. No other build/test from this session ran concurrently; other user and OS activity is not controlled. A single build is an observation, not a timing distribution.

Interpreting the native comparison

Every workload constructs a channel and timer before its loop, including the post-only loop. The initialized reactor remains part of that context. On this macOS/Boost combination, the native scheduler polls kqueue between posted completions. Therefore the ratios compare these initialized-reactor applications, not the intrinsic cost of an isolated coroutine or post. They must not be generalized to Linux, Windows, or a context that never initializes I/O. The native Cobalt runner also registers POSIX signals, unlike its WASI runner.

A separate diagnostic uses unmodified Boost and changes only whether it constructs an idle timer before 10,000 checked posts. Five pairs observed 59.5-98.9 ns/post without that timer and 10.50-12.15 us/post with it. This supports the initialized-reactor explanation for the large native post/channel ratios. It is a boundary check with fixed order and no discarded warmup, not a replacement statistical benchmark. Its source, command and output are retained as native-reactor-control files beside the results; the immutable source snapshot is .cpp.txt. Copy it to the recorded .cpp path before replaying that historical command. The main samples are unchanged.

Versioned toolchain diagnostics

8 WASIp3 LTO build configurations report the SDK 34 linker diagnostic function signature mismatch: cabi_realloc. A minimal malloc/printf program using only the SDK reproduces it and runs successfully in Wasmtime. The warning is preserved in build receipts; all measured payloads also pass their separate short execution checks. This does not establish that every canonical-ABI path is safe with this SDK/LTO combination. The primary runtime comparison uses no LTO. Native no-EH Cobalt retains its upstream promise diagnostic and issue-287 warning; neither warning is hidden or treated as proof that the affected move path is safe.

Baseline payload (KiB)

Profile Library O2 O2 + LTO O3 O3 + LTO Os Os + LTO Oz Oz + LTO

native-single-on

asio

116.53

107.97

116.53

108.08

118.69

91.39

115.06

99.33

native-single-on

cobalt

237.66

183.53

236.06

183.64

245.03

168.34

258.03

173.44

native-single-off

asio

88.03

81.33

87.48

81.05

90.83

81.83

102.73

87.20

native-single-off

cobalt

196.59

134.05

194.91

133.77

186.66

137.05

212.06

132.31

native-multi-on

asio

116.53

107.97

116.53

108.08

118.69

91.39

115.06

99.33

native-multi-on

cobalt

237.66

183.53

236.06

183.64

245.03

168.34

258.03

173.44

native-multi-off

asio

88.03

81.33

87.48

81.05

90.83

81.83

102.73

87.20

native-multi-off

cobalt

196.59

134.05

194.91

133.77

186.66

137.05

212.06

132.31

wasip2-single-on

asio

1048.99

743.46

1047.54

742.39

1048.14

741.21

1059.20

745.41

wasip2-single-on

cobalt

1504.96

1013.75

1502.76

1012.71

1526.98

1016.81

1585.76

1053.16

wasip2-single-off

asio

920.70

671.77

918.03

669.80

918.92

667.83

932.36

673.53

wasip2-single-off

cobalt

1384.36

950.20

1381.63

948.20

1406.83

951.55

1443.40

963.58

wasip3-single-on

asio

1154.12

840.33

1152.83

839.40

1152.57

837.76

1164.26

842.55

wasip3-single-on

cobalt

1602.26

1115.95

1600.25

1115.05

1623.50

1118.60

1682.94

1155.53

wasip3-single-off

asio

1040.12

781.24

1037.44

779.17

1037.74

776.50

1051.93

783.01

wasip3-single-off

cobalt

1480.71

1057.57

1477.89

1055.38

1502.52

1058.02

1539.83

1070.89

wasip3-multi-off

asio

1145.74

799.82

1143.13

798.26

1145.94

797.22

1162.28

802.89

wasip3-multi-off

cobalt

1565.32

1071.89

1562.55

1070.22

1574.31

1074.25

1627.81

1086.34

jspi-single-on

asio

153.83

159.28

153.18

158.94

146.32

146.25

142.67

138.40

jspi-single-on

cobalt

173.70

179.54

174.24

180.73

163.66

164.32

157.50

153.22

jspi-single-off

asio

137.84

138.91

136.13

137.28

130.27

129.83

128.58

126.47

jspi-single-off

cobalt

157.97

158.20

157.04

157.83

147.94

147.62

144.19

142.14

jspi-multi-on

asio

186.09

191.19

185.16

190.53

180.52

178.97

173.97

169.34

jspi-multi-on

cobalt

206.13

212.55

205.76

212.17

197.98

196.51

189.36

183.69

jspi-multi-off

asio

170.54

171.57

170.10

170.93

164.25

163.11

160.79

158.14

jspi-multi-off

cobalt

188.62

189.83

188.75

189.70

181.00

179.50

175.32

171.82

asyncify-single-on

asio

234.00

224.41

229.21

219.74

222.32

206.26

223.51

202.75

asyncify-single-on

cobalt

279.91

262.90

275.27

258.44

264.76

241.38

262.36

234.13

asyncify-single-off

asio

175.54

170.85

170.68

166.58

167.04

161.78

168.80

161.95

asyncify-single-off

cobalt

209.40

202.00

204.85

198.21

198.88

191.82

199.93

190.98

asyncify-multi-on

asio

300.67

289.45

290.86

281.14

288.68

271.62

284.08

260.63

asyncify-multi-on

cobalt

353.29

335.18

342.67

326.30

337.88

314.45

329.80

299.03

asyncify-multi-off

asio

231.42

231.33

225.68

225.64

220.67

217.28

220.75

216.46

asyncify-multi-off

cobalt

267.31

266.91

261.73

261.27

256.08

252.34

254.83

248.83

Workload payload (KiB)

Profile Library O2 O2 + LTO O3 O3 + LTO Os Os + LTO Oz Oz + LTO

native-single-on

asio

430.36

327.14

431.89

325.42

439.11

296.55

520.80

298.20

native-single-on

cobalt

517.12

407.08

532.09

407.12

501.44

365.59

573.75

358.09

native-single-off

asio

362.92

263.55

363.75

265.50

371.58

243.69

464.17

251.59

native-single-off

cobalt

421.77

309.08

419.16

323.41

408.14

287.92

490.67

303.34

native-multi-on

asio

430.36

327.14

431.89

325.42

439.11

296.55

520.80

298.20

native-multi-on

cobalt

517.12

407.08

532.09

407.12

501.44

365.59

573.75

358.09

native-multi-off

asio

362.92

263.55

363.75

265.50

371.58

243.69

464.17

251.59

native-multi-off

cobalt

421.77

309.08

419.16

323.41

408.14

287.92

490.67

303.34

wasip2-single-on

asio

1829.24

1218.96

1841.07

1224.74

1936.16

1246.52

2186.69

1280.91

wasip2-single-on

cobalt

1851.02

1255.85

1850.45

1256.73

1877.98

1251.53

2025.85

1281.17

wasip2-single-off

asio

1664.43

1151.15

1663.11

1154.85

1761.48

1163.21

2003.72

1181.12

wasip2-single-off

cobalt

1681.74

1181.23

1675.41

1179.46

1714.51

1173.84

1848.80

1180.41

wasip3-single-on

asio

1929.09

1320.45

1940.83

1326.49

2026.98

1341.07

2285.22

1382.52

wasip3-single-on

cobalt

1951.96

1358.60

1951.46

1359.74

1969.76

1346.83

2125.34

1383.80

wasip3-single-off

asio

1761.63

1260.49

1760.12

1264.20

1850.46

1264.99

2100.84

1290.19

wasip3-single-off

cobalt

1779.17

1291.43

1772.58

1290.44

1803.66

1276.24

1946.11

1290.18

wasip3-multi-off

asio

1848.70

1284.83

1847.49

1288.54

1925.19

1290.25

2190.89

1314.30

wasip3-multi-off

cobalt

1866.37

1308.85

1859.36

1307.16

1878.36

1295.06

2036.01

1307.41

jspi-single-on

asio

249.83

262.50

251.81

261.40

227.08

223.55

210.50

200.86

jspi-single-on

cobalt

307.08

323.72

310.46

326.24

265.20

263.28

241.38

231.31

jspi-single-off

asio

229.74

228.92

233.81

233.38

203.59

198.86

193.67

187.21

jspi-single-off

cobalt

277.83

274.97

277.89

275.19

236.27

234.23

219.62

212.46

jspi-multi-on

asio

282.71

292.64

283.25

290.28

261.30

255.29

242.69

231.58

jspi-multi-on

cobalt

340.49

352.54

342.48

351.21

300.05

295.55

274.44

262.52

jspi-multi-off

asio

261.36

262.43

265.31

266.57

236.29

230.31

224.77

217.08

jspi-multi-off

cobalt

309.11

309.07

308.35

308.22

269.99

266.99

251.31

242.57

asyncify-single-on

asio

443.42

421.58

429.23

406.37

413.28

363.44

393.89

335.03

asyncify-single-on

cobalt

574.26

531.36

556.13

518.95

497.62

440.36

470.64

403.60

asyncify-single-off

asio

334.23

319.27

339.30

325.17

300.79

284.02

296.64

276.64

asyncify-single-off

cobalt

411.16

391.64

404.72

385.66

358.95

343.04

350.96

327.90

asyncify-multi-on

asio

520.30

495.71

501.08

477.87

488.43

436.68

464.02

402.14

asyncify-multi-on

cobalt

657.06

611.93

633.34

594.83

579.05

522.40

545.80

478.29

asyncify-multi-off

asio

397.75

391.73

401.07

395.28

359.61

346.31

353.46

337.05

asyncify-multi-off

cobalt

477.63

469.22

468.34

459.56

422.30

411.60

411.00

392.31

Runtime and memory scope

Each operation is one completed iteration: post resumes once; immediate sends then receives in a buffered Asio channel; channel transfers one value through an unbuffered channel; parallel joins one Asio-channel send/receive pair; allocation performs five posts and five arena allocations; timer awaits a zero-expiry timer; http parses one complete in-memory HTTP response. Asio uses parallel_group and Cobalt uses join for paired operations. HTTP does not measure network or TLS latency. Every iteration contributes to a checked checksum.

Thirty fresh executions per workload/profile use frozen common operation counts and an in-process warmup. The report records median, p95, min/max and a bootstrap 95% interval for the median. Ten baseline starts measure fresh process/page startup. The browser process is retained; each page/worker is new, with no-store HTTP. OS and engine caches are not cleared, so these are not cold-machine or empty-code-cache measurements. The explicit buffered loader measures fetch, compile and instantiate separately; it does not represent the default streaming loader.

Three instrumented executions describe C++ allocation counts/requested bytes and Cobalt frame PMR requests. Those nested counters must not be added. Direct C malloc and JavaScript allocations are outside their scope. Wasm linear memory is capacity, not live heap. Process RSS includes Node/Wasmtime; browser-module RSS/CPU are unavailable. Instrumentation timing is retained only as a diagnostic, not a comparative performance claim.

Asio median time per operation (ns)

Profile Host Post Immediate Channel Parallel Allocation Timer HTTP parse

asyncify-multi-off

node

827.2

2041.2

1388.9

1390.6

3853.5

3784.6

428.1

asyncify-multi-off

page

718.0

1772.5

1376.9

1357.5

3681.5

3408.2

382.1

asyncify-multi-off

worker

717.8

1762.8

1413.6

1418.4

3886.5

3393.6

397.0

asyncify-multi-on

node

3793.1

8164.8

4531.1

4519.8

15444.5

5380.2

548.0

asyncify-multi-on

page

2793.2

6528.2

4030.8

4003.9

12636.5

5339.2

446.5

asyncify-multi-on

worker

2746.5

6421.2

4021.0

3999.1

12490.5

4992.6

450.4

asyncify-single-off

node

950.3

2306.2

1370.3

1362.4

4345.3

4676.8

364.4

asyncify-single-off

page

649.4

1660.2

1093.8

1093.8

3232.4

3098.1

339.4

asyncify-single-off

worker

642.1

1611.3

1071.8

1064.5

3183.6

2998.0

341.8

asyncify-single-on

node

3765.8

7910.0

4343.9

4382.5

15651.9

4649.1

502.7

asyncify-single-on

page

2822.3

6323.2

3681.6

3664.6

12460.9

4392.1

398.9

asyncify-single-on

worker

2778.3

6206.1

3664.6

3625.5

12187.5

4348.1

400.7

jspi-multi-off

node

856.1

2104.0

1142.2

1139.5

3863.5

2102.8

329.9

jspi-multi-off

page

529.8

1396.5

1044.8

1042.5

2695.0

2214.2

307.0

jspi-multi-off

worker

517.5

1381.8

1035.2

1037.6

2627.5

2187.5

307.9

jspi-multi-on

node

904.2

2258.8

1199.4

1204.1

4018.5

2122.9

326.5

jspi-multi-on

page

581.0

1514.0

1130.4

1135.1

2871.0

2258.4

309.5

jspi-multi-on

worker

566.5

1513.5

1130.4

1128.0

2812.0

2221.5

311.6

jspi-single-off

node

784.0

1623.0

1190.9

1187.4

3661.2

1873.8

296.7

jspi-single-off

page

473.6

1289.1

869.1

876.5

2392.6

1826.2

287.5

jspi-single-off

worker

468.8

1289.1

859.4

854.5

2343.8

1796.9

289.6

jspi-single-on

node

853.9

2051.8

1397.8

1393.5

3899.8

1923.9

299.0

jspi-single-on

page

522.5

1430.7

961.9

959.5

2597.7

1855.5

288.7

jspi-single-on

worker

517.6

1401.4

954.6

942.4

2597.7

1955.6

289.9

native-multi-off

native

11873.1

24188.8

11739.4

11883.9

59530.9

642.4

121.9

native-multi-on

native

11587.2

23116.1

11974.8

12015.5

58142.3

652.6

119.3

native-single-off

native

12030.5

23807.9

12106.9

11880.9

59910.4

643.6

118.3

native-single-on

native

11360.7

24102.0

12065.1

12027.5

56108.8

652.2

120.5

wasip2-single-off

wasmtime

167.8

486.5

284.4

280.4

855.1

851.6

236.2

wasip2-single-on

wasmtime

268.7

768.6

499.7

493.3

1369.9

920.1

244.7

wasip3-multi-off

wasmtime

212.7

618.6

365.3

365.7

1095.9

837.5

240.7

wasip3-single-off

wasmtime

180.3

512.3

294.5

295.2

936.4

766.8

238.2

wasip3-single-on

wasmtime

268.7

778.0

505.8

507.9

1385.7

824.7

247.7

Cobalt median time per operation (ns)

Profile Host Post Immediate Channel Parallel Allocation Timer HTTP parse

asyncify-multi-off

node

2534.1

1090.5

2693.8

3745.5

11211.0

5441.1

455.3

asyncify-multi-off

page

2500.0

1142.5

2509.8

3903.8

12539.5

3525.4

395.8

asyncify-multi-off

worker

2636.8

1182.0

2585.5

3964.9

11845.5

3415.6

410.8

asyncify-multi-on

node

5723.2

5412.8

5024.1

7440.6

26678.0

5354.9

557.2

asyncify-multi-on

page

5747.0

5473.5

4919.5

7534.2

25820.5

5315.0

444.7

asyncify-multi-on

worker

5720.1

5376.0

4995.1

7492.6

25136.5

4995.2

441.3

asyncify-single-off

node

2846.7

1071.5

3001.0

3912.3

15319.9

4765.3

388.3

asyncify-single-off

page

2336.4

1132.8

2299.8

3596.2

10849.6

2973.6

353.4

asyncify-single-off

worker

2319.3

1132.8

2292.5

3625.5

11367.2

2973.6

355.8

asyncify-single-on

node

4987.2

5331.0

4517.9

6390.8

22082.5

4720.4

514.8

asyncify-single-on

page

4877.9

5405.3

4165.0

6367.2

23242.2

4528.8

399.8

asyncify-single-on

worker

4973.1

5317.4

4199.2

6616.2

22627.0

4389.6

405.3

jspi-multi-off

node

1433.9

885.0

1441.2

2300.8

6860.0

2085.1

361.8

jspi-multi-off

page

1350.1

976.5

1335.5

2253.5

6386.5

2275.5

311.9

jspi-multi-off

worker

1318.2

976.5

1306.1

2243.8

6739.0

2246.1

314.3

jspi-multi-on

node

1496.5

934.2

1490.0

2366.8

7130.0

2175.8

360.1

jspi-multi-on

page

1411.1

981.5

1398.9

2304.8

6709.5

2309.5

316.2

jspi-multi-on

worker

1382.0

986.2

1372.0

2304.6

7168.0

2299.8

320.8

jspi-single-off

node

1332.7

875.7

1293.5

2245.7

6102.5

1859.8

318.2

jspi-single-off

page

1206.1

966.8

1169.4

2070.3

5761.7

1860.4

291.7

jspi-single-off

worker

1189.0

981.4

1142.6

2033.7

5605.5

1972.7

295.4

jspi-single-on

node

1381.7

931.6

1349.1

2315.2

6410.2

1960.4

322.7

jspi-single-on

page

1264.6

1001.0

1225.6

2121.6

6035.2

1928.7

296.0

jspi-single-on

worker

1247.6

1005.9

1210.9

2148.4

5957.0

2031.2

297.5

native-multi-off

native

11994.1

129.4

12053.3

12130.8

60000.9

642.8

119.9

native-multi-on

native

12159.1

126.1

11954.7

12131.5

60672.0

648.7

119.1

native-single-off

native

12097.6

129.3

11968.5

12111.7

60581.2

641.8

121.5

native-single-on

native

12124.8

126.5

11969.7

12074.7

60563.2

656.8

119.3

wasip2-single-off

wasmtime

184.6

319.2

166.2

507.2

937.4

859.3

240.0

wasip2-single-on

wasmtime

301.8

467.3

266.2

755.3

1520.3

904.4

245.5

wasip3-multi-off

wasmtime

218.5

343.6

194.8

578.2

1116.1

836.5

239.3

wasip3-single-off

wasmtime

191.7

331.0

179.5

534.3

971.1

763.0

237.2

wasip3-single-on

wasmtime

299.2

474.4

270.9

769.4

1534.2

805.8

252.3

Baseline startup and instrumented allocation workload

Startup is the median of ten fresh starts. Process wall time includes harness setup, runtime launch and waiting; browser wall time begins inside a fresh page/worker, after its host page navigation, and includes buffered module loading. They are different observation boundaries. n/a means unavailable, not zero. Memory columns below use three instrumented allocation-workload runs. Complete workload-specific memory distributions and separate JS/Wasm/native payload bytes are in the CSV files.

Profile Host Library Start (ms) C++ allocations C++ peak (bytes) Frame peak (bytes) Linear capacity (KiB) Process RSS (MiB)

asyncify-multi-off

node

asio

74.66

0.00

1077.00

n/a

16384.00

74.00

asyncify-multi-off

node

cobalt

75.66

0.00

272051.00

11664.00

16384.00

76.64

asyncify-multi-off

page

asio

6.89

0.00

1077.00

n/a

16384.00

n/a

asyncify-multi-off

page

cobalt

8.14

0.00

272051.00

11664.00

16384.00

n/a

asyncify-multi-off

worker

asio

6.07

0.00

1077.00

n/a

16384.00

n/a

asyncify-multi-off

worker

cobalt

7.34

0.00

272051.00

11664.00

16384.00

n/a

asyncify-multi-on

node

asio

74.53

0.00

1077.00

n/a

16384.00

67.75

asyncify-multi-on

node

cobalt

76.43

0.00

272051.00

12048.00

16384.00

77.19

asyncify-multi-on

page

asio

7.57

0.00

1077.00

n/a

16384.00

n/a

asyncify-multi-on

page

cobalt

9.21

0.00

272051.00

12048.00

16384.00

n/a

asyncify-multi-on

worker

asio

6.65

0.00

1077.00

n/a

16384.00

n/a

asyncify-multi-on

worker

cobalt

8.27

0.00

272051.00

12048.00

16384.00

n/a

asyncify-single-off

node

asio

73.15

0.00

937.00

n/a

16512.00

71.45

asyncify-single-off

node

cobalt

73.75

0.00

271911.00

11664.00

16512.00

80.03

asyncify-single-off

page

asio

6.24

0.00

937.00

n/a

16512.00

n/a

asyncify-single-off

page

cobalt

7.29

0.00

271911.00

11664.00

16512.00

n/a

asyncify-single-off

worker

asio

5.38

0.00

937.00

n/a

16512.00

n/a

asyncify-single-off

worker

cobalt

6.51

0.00

271911.00

11664.00

16512.00

n/a

asyncify-single-on

node

asio

74.28

0.00

937.00

n/a

16512.00

66.55

asyncify-single-on

node

cobalt

74.99

0.00

271911.00

12048.00

16512.00

73.48

asyncify-single-on

page

asio

6.84

0.00

937.00

n/a

16512.00

n/a

asyncify-single-on

page

cobalt

8.06

0.00

271911.00

12048.00

16512.00

n/a

asyncify-single-on

worker

asio

5.88

0.00

937.00

n/a

16512.00

n/a

asyncify-single-on

worker

cobalt

7.20

0.00

271911.00

12048.00

16512.00

n/a

jspi-multi-off

node

asio

74.61

0.00

1077.00

n/a

16384.00

61.09

jspi-multi-off

node

cobalt

75.46

0.00

272051.00

11664.00

16384.00

62.67

jspi-multi-off

page

asio

6.99

0.00

1077.00

n/a

16384.00

n/a

jspi-multi-off

page

cobalt

7.80

0.00

272051.00

11664.00

16384.00

n/a

jspi-multi-off

worker

asio

6.05

0.00

1077.00

n/a

16384.00

n/a

jspi-multi-off

worker

cobalt

6.87

0.00

272051.00

11664.00

16384.00

n/a

jspi-multi-on

node

asio

74.26

0.00

1077.00

n/a

16384.00

62.92

jspi-multi-on

node

cobalt

75.45

0.00

1058483.00

33936.00

16384.00

64.94

jspi-multi-on

page

asio

7.06

0.00

1077.00

n/a

16384.00

n/a

jspi-multi-on

page

cobalt

7.94

0.00

1058483.00

33936.00

16384.00

n/a

jspi-multi-on

worker

asio

6.32

0.00

1077.00

n/a

16384.00

n/a

jspi-multi-on

worker

cobalt

7.27

0.00

1058483.00

33936.00

16384.00

n/a

jspi-single-off

node

asio

73.09

0.00

937.00

n/a

16512.00

61.28

jspi-single-off

node

cobalt

73.55

0.00

271911.00

11664.00

16512.00

62.31

jspi-single-off

page

asio

6.53

0.00

937.00

n/a

16512.00

n/a

jspi-single-off

page

cobalt

7.11

0.00

271911.00

11664.00

16512.00

n/a

jspi-single-off

worker

asio

5.62

0.00

937.00

n/a

16512.00

n/a

jspi-single-off

worker

cobalt

6.34

0.00

271911.00

11664.00

16512.00

n/a

jspi-single-on

node

asio

73.27

0.00

937.00

n/a

16512.00

62.92

jspi-single-on

node

cobalt

74.49

0.00

1058343.00

33936.00

16512.00

63.12

jspi-single-on

page

asio

6.62

0.00

937.00

n/a

16512.00

n/a

jspi-single-on

page

cobalt

7.43

0.00

1058343.00

33936.00

16512.00

n/a

jspi-single-on

worker

asio

5.78

0.00

937.00

n/a

16512.00

n/a

jspi-single-on

worker

cobalt

6.61

0.00

1058343.00

33936.00

16512.00

n/a

native-multi-off

native

asio

3.15

0.00

930.00

n/a

n/a

9.25

native-multi-off

native

cobalt

3.05

0.00

272303.00

12352.00

n/a

9.25

native-multi-on

native

asio

2.99

0.00

930.00

n/a

n/a

9.25

native-multi-on

native

cobalt

3.15

0.00

272303.00

13040.00

n/a

9.25

native-single-off

native

asio

2.96

0.00

930.00

n/a

n/a

9.25

native-single-off

native

cobalt

3.08

0.00

272303.00

12352.00

n/a

9.25

native-single-on

native

asio

3.15

0.00

930.00

n/a

n/a

9.25

native-single-on

native

cobalt

3.03

0.00

272303.00

13040.00

n/a

9.25

wasip2-single-off

wasmtime

asio

7.53

0.00

12746.00

n/a

128.00

15.11

wasip2-single-off

wasmtime

cobalt

8.61

0.00

283281.00

11680.00

384.00

15.86

wasip2-single-on

wasmtime

asio

8.21

0.00

12746.00

n/a

128.00

16.27

wasip2-single-on

wasmtime

cobalt

8.61

0.00

1069713.00

33936.00

1152.00

17.23

wasip3-multi-off

wasmtime

asio

8.23

0.00

12906.00

n/a

128.00

15.70

wasip3-multi-off

wasmtime

cobalt

9.22

0.00

283441.00

11680.00

448.00

16.28

wasip3-single-off

wasmtime

asio

7.46

0.00

12766.00

n/a

128.00

15.48

wasip3-single-off

wasmtime

cobalt

8.78

0.00

283301.00

11680.00

384.00

16.08

wasip3-single-on

wasmtime

asio

8.18

0.00

12766.00

n/a

128.00

16.56

wasip3-single-on

wasmtime

cobalt

9.34

0.00

1069733.00

33936.00

1216.00

17.50

Buffered browser startup phases (ms)

Each column is an independent median of ten empty-runner observations. Fetch covers the Wasm response. Medians do not necessarily add; runtime-ready also includes JavaScript loading and setup.

Profile Host Library Fetch Compile Instantiate Runtime ready

asyncify-multi-off

page

asio

0.59

0.33

0.12

5.58

asyncify-multi-off

page

cobalt

0.62

0.38

0.14

5.65

asyncify-multi-off

worker

asio

0.49

0.33

0.12

4.79

asyncify-multi-off

worker

cobalt

0.52

0.38

0.13

4.90

asyncify-multi-on

page

asio

0.62

0.40

0.15

5.90

asyncify-multi-on

page

cobalt

0.68

0.45

0.16

6.10

asyncify-multi-on

worker

asio

0.52

0.39

0.15

5.03

asyncify-multi-on

worker

cobalt

0.53

0.45

0.15

5.16

asyncify-single-off

page

asio

0.62

0.28

0.07

4.98

asyncify-single-off

page

cobalt

0.64

0.33

0.07

5.01

asyncify-single-off

worker

asio

0.47

0.28

0.06

4.17

asyncify-single-off

worker

cobalt

0.49

0.32

0.06

4.25

asyncify-single-on

page

asio

0.65

0.36

0.09

5.31

asyncify-single-on

page

cobalt

0.61

0.40

0.09

5.25

asyncify-single-on

worker

asio

0.49

0.36

0.08

4.37

asyncify-single-on

worker

cobalt

0.52

0.37

0.09

4.47

jspi-multi-off

page

asio

0.60

0.29

0.57

5.98

jspi-multi-off

page

cobalt

0.62

0.34

0.59

6.07

jspi-multi-off

worker

asio

0.47

0.30

0.55

5.06

jspi-multi-off

worker

cobalt

0.46

0.33

0.56

5.17

jspi-multi-on

page

asio

0.58

0.33

0.58

5.97

jspi-multi-on

page

cobalt

0.59

0.36

0.58

6.04

jspi-multi-on

worker

asio

0.49

0.34

0.56

5.22

jspi-multi-on

worker

cobalt

0.53

0.36

0.59

5.36

jspi-single-off

page

asio

0.64

0.26

0.52

5.51

jspi-single-off

page

cobalt

0.58

0.30

0.52

5.42

jspi-single-off

worker

asio

0.48

0.27

0.50

4.60

jspi-single-off

worker

cobalt

0.49

0.29

0.50

4.67

jspi-single-on

page

asio

0.60

0.30

0.52

5.47

jspi-single-on

page

cobalt

0.63

0.32

0.51

5.54

jspi-single-on

worker

asio

0.48

0.29

0.51

4.69

jspi-single-on

worker

cobalt

0.49

0.34

0.51

4.73

Complete evidence and plots

bench/results/2026-11-07 contains sizes.csv, metrics.csv, summary.json, environment metadata and the raw evidence archive with its SHA-256 file. The archive retains commands, build logs, source/artifact hashes, calibration, frozen counts and every independent sample. The local experiment is not remote CI evidence.

2026-11-07T01:30:54.864156 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ post immediate channel parallel allocation timer http asyncify-multi-off / node asyncify-multi-off / page asyncify-multi-off / worker asyncify-multi-on / node asyncify-multi-on / page asyncify-multi-on / worker asyncify-single-off / node asyncify-single-off / page asyncify-single-off / worker asyncify-single-on / node asyncify-single-on / page asyncify-single-on / worker jspi-multi-off / node jspi-multi-off / page jspi-multi-off / worker jspi-multi-on / node jspi-multi-on / page jspi-multi-on / worker jspi-single-off / node jspi-single-off / page jspi-single-off / worker jspi-single-on / node jspi-single-on / page jspi-single-on / worker native-multi-off / native native-multi-on / native native-single-off / native native-single-on / native wasip2-single-off / wasmtime wasip2-single-on / wasmtime wasip3-multi-off / wasmtime wasip3-single-off / wasmtime wasip3-single-on / wasmtime 0.07 0.08 0.12 0.12 0.06 5.89 3.51 0.06 0.07 0.12 0.11 0.06 5.31 3.13 0.06 0.07 0.12 0.12 0.07 5.28 3.26 0.33 0.35 0.38 0.38 0.27 8.24 4.59 0.24 0.28 0.34 0.33 0.22 8.18 3.74 0.24 0.28 0.34 0.33 0.21 7.65 3.77 0.08 0.10 0.11 0.11 0.07 7.27 3.08 0.05 0.07 0.09 0.09 0.05 4.81 2.87 0.05 0.07 0.09 0.09 0.05 4.66 2.89 0.33 0.33 0.36 0.36 0.28 7.13 4.17 0.25 0.26 0.31 0.30 0.22 6.73 3.31 0.24 0.26 0.30 0.30 0.22 6.67 3.32 0.07 0.09 0.10 0.10 0.06 3.27 2.71 0.04 0.06 0.09 0.09 0.05 3.45 2.52 0.04 0.06 0.09 0.09 0.04 3.41 2.53 0.08 0.10 0.10 0.10 0.07 3.25 2.74 0.05 0.07 0.09 0.09 0.05 3.46 2.59 0.05 0.07 0.09 0.09 0.05 3.40 2.61 0.07 0.07 0.10 0.10 0.06 2.91 2.51 0.04 0.05 0.07 0.07 0.04 2.84 2.43 0.04 0.05 0.07 0.07 0.04 2.79 2.45 0.08 0.09 0.12 0.12 0.07 2.95 2.48 0.05 0.06 0.08 0.08 0.05 2.84 2.40 0.05 0.06 0.08 0.08 0.05 3.00 2.41 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 0.01 0.02 0.02 0.02 0.01 1.32 2.00 0.02 0.03 0.04 0.04 0.02 1.41 2.03 0.02 0.03 0.03 0.03 0.02 1.30 1.97 0.01 0.02 0.02 0.02 0.02 1.19 2.01 0.02 0.03 0.04 0.04 0.02 1.26 2.05 1 0 − 1 1 0 0 Ratio to native Asio execution relative to native Median of 30 fresh executions; O3, no LTO. 1.00 = native; lower is faster. All workloads initialize a timer/reactor. Native macOS kqueue polling affects these ratios; see diagnostic.
Figure 1. Asio execution relative to native
2026-11-07T01:30:55.520480 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ post immediate channel parallel allocation timer http asyncify-multi-off / node asyncify-multi-off / page asyncify-multi-off / worker asyncify-multi-on / node asyncify-multi-on / page asyncify-multi-on / worker asyncify-single-off / node asyncify-single-off / page asyncify-single-off / worker asyncify-single-on / node asyncify-single-on / page asyncify-single-on / worker jspi-multi-off / node jspi-multi-off / page jspi-multi-off / worker jspi-multi-on / node jspi-multi-on / page jspi-multi-on / worker jspi-single-off / node jspi-single-off / page jspi-single-off / worker jspi-single-on / node jspi-single-on / page jspi-single-on / worker native-multi-off / native native-multi-on / native native-single-off / native native-single-on / native wasip2-single-off / wasmtime wasip2-single-on / wasmtime wasip3-multi-off / wasmtime wasip3-single-off / wasmtime wasip3-single-on / wasmtime 0.21 8.43 0.22 0.31 0.19 8.46 3.80 0.21 8.83 0.21 0.32 0.21 5.48 3.30 0.22 9.13 0.21 0.33 0.20 5.31 3.43 0.47 42.91 0.42 0.61 0.44 8.26 4.68 0.47 43.39 0.41 0.62 0.43 8.19 3.73 0.47 42.62 0.42 0.62 0.41 7.70 3.71 0.24 8.29 0.25 0.32 0.25 7.42 3.20 0.19 8.76 0.19 0.30 0.18 4.63 2.91 0.19 8.76 0.19 0.30 0.19 4.63 2.93 0.41 42.14 0.38 0.53 0.36 7.19 4.32 0.40 42.73 0.35 0.53 0.38 6.90 3.35 0.41 42.03 0.35 0.55 0.37 6.68 3.40 0.12 6.84 0.12 0.19 0.11 3.24 3.02 0.11 7.55 0.11 0.19 0.11 3.54 2.60 0.11 7.55 0.11 0.18 0.11 3.49 2.62 0.12 7.41 0.12 0.20 0.12 3.35 3.02 0.12 7.78 0.12 0.19 0.11 3.56 2.66 0.11 7.82 0.11 0.19 0.12 3.55 2.69 0.11 6.77 0.11 0.19 0.10 2.90 2.62 0.10 7.48 0.10 0.17 0.10 2.90 2.40 0.10 7.59 0.10 0.17 0.09 3.07 2.43 0.11 7.36 0.11 0.19 0.11 2.98 2.71 0.10 7.91 0.10 0.18 0.10 2.94 2.48 0.10 7.95 0.10 0.18 0.10 3.09 2.49 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 0.02 2.47 0.01 0.04 0.02 1.34 1.98 0.02 3.69 0.02 0.06 0.03 1.38 2.06 0.02 2.66 0.02 0.05 0.02 1.30 2.00 0.02 2.56 0.01 0.04 0.02 1.19 1.95 0.02 3.75 0.02 0.06 0.03 1.23 2.12 1 0 − 1 1 0 0 1 0 1 Ratio to native Cobalt execution relative to native Median of 30 fresh executions; O3, no LTO. 1.00 = native; lower is faster. All workloads initialize a timer/reactor. Native macOS kqueue polling affects these ratios; see diagnostic.
Figure 2. Cobalt execution relative to native
2026-11-07T01:30:56.091805 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ O2 O2 + LTO O3 O3 + LTO Os Os + LTO Oz Oz + LTO asyncify-multi-off asyncify-multi-on asyncify-single-off asyncify-single-on jspi-multi-off jspi-multi-on jspi-single-off jspi-single-on native-multi-off native-multi-on native-single-off native-single-on wasip2-single-off wasip2-single-on wasip3-multi-off wasip3-single-off wasip3-single-on 397.75 391.73 401.07 395.28 359.61 346.31 353.46 337.05 520.30 495.71 501.08 477.87 488.43 436.68 464.02 402.14 334.23 319.27 339.30 325.17 300.79 284.02 296.64 276.64 443.42 421.58 429.23 406.37 413.28 363.44 393.89 335.03 261.36 262.43 265.31 266.57 236.29 230.31 224.77 217.08 282.71 292.64 283.25 290.28 261.30 255.29 242.69 231.58 229.74 228.92 233.81 233.38 203.59 198.86 193.67 187.21 249.83 262.50 251.81 261.40 227.08 223.55 210.50 200.86 362.92 263.55 363.75 265.50 371.58 243.69 464.17 251.59 430.36 327.14 431.89 325.42 439.11 296.55 520.80 298.20 362.92 263.55 363.75 265.50 371.58 243.69 464.17 251.59 430.36 327.14 431.89 325.42 439.11 296.55 520.80 298.20 1664.43 1151.15 1663.11 1154.85 1761.48 1163.21 2003.72 1181.12 1829.24 1218.96 1841.07 1224.74 1936.16 1246.52 2186.69 1280.91 1848.70 1284.83 1847.49 1288.54 1925.19 1290.25 2190.89 1314.30 1761.63 1260.49 1760.12 1264.20 1850.46 1264.99 2100.84 1290.19 1929.09 1320.45 1940.83 1326.49 2026.98 1341.07 2285.22 1382.52 1 0 0 1 0 1 1 0 2 1 0 3 KiB Asio workload payload Release, uninstrumented. Native executable; WASI component; Emscripten JavaScript + Wasm. Raw KiB.
Figure 3. Asio Release payload
2026-11-07T01:30:56.577211 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ O2 O2 + LTO O3 O3 + LTO Os Os + LTO Oz Oz + LTO asyncify-multi-off asyncify-multi-on asyncify-single-off asyncify-single-on jspi-multi-off jspi-multi-on jspi-single-off jspi-single-on native-multi-off native-multi-on native-single-off native-single-on wasip2-single-off wasip2-single-on wasip3-multi-off wasip3-single-off wasip3-single-on 477.63 469.22 468.34 459.56 422.30 411.60 411.00 392.31 657.06 611.93 633.34 594.83 579.05 522.40 545.80 478.29 411.16 391.64 404.72 385.66 358.95 343.04 350.96 327.90 574.26 531.36 556.13 518.95 497.62 440.36 470.64 403.60 309.11 309.07 308.35 308.22 269.99 266.99 251.31 242.57 340.49 352.54 342.48 351.21 300.05 295.55 274.44 262.52 277.83 274.97 277.89 275.19 236.27 234.23 219.62 212.46 307.08 323.72 310.46 326.24 265.20 263.28 241.38 231.31 421.77 309.08 419.16 323.41 408.14 287.92 490.67 303.34 517.12 407.08 532.09 407.12 501.44 365.59 573.75 358.09 421.77 309.08 419.16 323.41 408.14 287.92 490.67 303.34 517.12 407.08 532.09 407.12 501.44 365.59 573.75 358.09 1681.74 1181.23 1675.41 1179.46 1714.51 1173.84 1848.80 1180.41 1851.02 1255.85 1850.45 1256.73 1877.98 1251.53 2025.85 1281.17 1866.37 1308.85 1859.36 1307.16 1878.36 1295.06 2036.01 1307.41 1779.17 1291.43 1772.58 1290.44 1803.66 1276.24 1946.11 1290.18 1951.96 1358.60 1951.46 1359.74 1969.76 1346.83 2125.34 1383.80 1 0 0 1 0 1 1 0 2 1 0 3 KiB Cobalt workload payload Release, uninstrumented. Native executable; WASI component; Emscripten JavaScript + Wasm. Raw KiB.
Figure 4. Cobalt Release payload
2026-11-07T01:30:57.028897 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ O2 O2 + LTO O3 O3 + LTO Os Os + LTO Oz Oz + LTO asyncify-multi-off asyncify-multi-on asyncify-single-off asyncify-single-on jspi-multi-off jspi-multi-on jspi-single-off jspi-single-on native-multi-off native-multi-on native-single-off native-single-on wasip2-single-off wasip2-single-on wasip3-multi-off wasip3-single-off wasip3-single-on 11.27 12.06 12.27 13.00 11.68 12.24 11.45 11.78 11.81 12.49 12.77 13.24 12.09 12.52 11.48 12.38 10.70 11.30 11.48 12.31 11.17 11.60 10.51 11.04 11.02 12.23 12.43 12.66 11.69 12.39 11.39 11.91 11.02 11.73 11.49 12.39 11.07 11.72 10.94 11.55 11.33 12.00 11.62 12.98 11.12 12.20 11.39 11.86 10.46 10.96 11.17 11.79 10.67 11.21 10.32 10.99 11.19 11.98 11.93 12.81 10.66 11.96 10.47 11.70 9.91 9.87 10.02 9.99 9.27 9.08 8.94 8.80 10.30 10.41 10.36 10.42 9.60 9.80 9.20 9.19 9.68 9.90 9.83 9.98 9.20 9.10 8.89 8.91 10.15 10.32 10.32 10.42 9.64 9.64 9.14 9.29 10.69 11.74 10.66 11.91 10.11 11.34 9.76 10.95 11.17 12.33 11.22 12.20 10.62 11.51 10.25 11.70 11.26 11.44 11.25 11.43 10.65 10.91 10.42 10.64 10.68 12.06 10.58 11.95 10.12 11.44 9.78 11.04 10.90 12.44 11.21 12.43 10.70 12.28 10.30 11.90 1 0 0 1 0 1 Seconds Forced Release build of six programs One observation per setting; three compiler jobs, warm SDK cache. Not a timing distribution.
Figure 5. Observed compilation times

Guarantees

  1. Native core coroutine and plain I/O types retain their Boost.Cobalt identity. The corrected SSL wrapper is the documented exception.

  2. Consumer builds use shipped source files and explicit dependencies. They do not patch Boost or select replacement Boost include trees.

  3. The browser runner uses Asio’s configured handler limit. This limit is checked between handlers, not inside a running handler.

  4. A failed or cancelled handshake on the corrected SSL stream prevents subsequent application I/O from falling back to plaintext.

Reference

The generated reference documents WebCPP’s additions and configuration. The Boost.Cobalt 1.92 reference describes the inherited coroutine concepts and operations; target restrictions and the SSL exception below also apply.

Macros

Name Description

WEBCPP_COBALT_FOR

Iterates an asynchronous range with the selected coroutine backend.

WEBCPP_COBALT_HAS_BROWSER_BRIDGE

1 when JavaScript Promises and events can be awaited through the Asio browser bridge.

WEBCPP_COBALT_HAS_BROWSER_WORKERS

1 for an Emscripten pthread configuration; browser isolation and worker hosting are runtime requirements.

WEBCPP_COBALT_HAS_HOST_DNS

1 when the backend provides forward lookup; the host can still deny network or DNS capabilities.

WEBCPP_COBALT_HAS_LOCAL_SOCKETS

1 when native Boost.Asio supplies local sockets; WASI and browser transports do not impersonate Unix sockets.

WEBCPP_COBALT_HAS_OPENSSL_BACKEND

1 when the target can link guest OpenSSL; select io_ssl or cobalt_ssl separately.

WEBCPP_COBALT_HAS_PIPE_CREATION

1 when guest-created asynchronous pipes support transfer, cancellation and EOF.

WEBCPP_COBALT_HAS_POLLABLE_STDIO

1 when Asio’s explicit WASIp2 pollable stdio adapter is available with Cobalt tokens.

WEBCPP_COBALT_HAS_POSIX_STDIO

1 when native POSIX stdio descriptors can participate in asynchronous stream operations.

WEBCPP_COBALT_HAS_REVERSE_DNS

1 when native reverse lookup is available; WASI address lookup is forward-only.

WEBCPP_COBALT_HAS_SERIAL_PORT

1 when the native backend supplies serial ports; a browser or WASI host adapter is a separate facility.

WEBCPP_COBALT_HAS_SIGNALS

1 when native process-signal delivery is available; application cancellation remains available elsewhere.

WEBCPP_COBALT_HAS_SOCKET_BACKEND

1 when the configured Asio backend provides native or WASI TCP/UDP; host grants remain runtime requirements.

WEBCPP_COBALT_HAS_THREADS

1 when the configured executor supports threads; WASIp3 cooperative threads are not CPU parallelism.

WEBCPP_COBALT_NO_EXCEPTIONS

Defined when WebCPP’s Cobalt adapters are configured without exceptions.

webcpp::cobalt

Native coroutine types retain Boost identity; the SSL wrapper is corrected separately.

Namespaces

Name

io

webcpp::cobalt::io

Functions

Name Description

read

Reads the complete buffer through the corrected native SSL wrapper.

write

Writes the complete buffer through the corrected native SSL wrapper.

Using Declarations

Name Description

read

Retains Boost’s composed reads for native non-SSL stream types.

write

Retains Boost’s composed writes for native non-SSL stream types.

webcpp::cobalt::io::read

Reads the complete buffer through the corrected native SSL wrapper.

Synopsis

/* implementation-defined */
read(
    ssl::stream& stream,
    mutable_buffer_sequence const& buffers);

Description

The operation starts when awaited. The stream and buffer storage must outlive completion. Cancellation returns operation_aborted and the transferred count. Keep the concrete SSL stream type when selecting this overload; erasing it to Boost’s generic stream selects the upstream composition and its limitations.

Return Value

A lazy operation with completion signature void(error_code, size_t).

Parameters

Name Description

stream

SSL stream, or a STARTTLS stream before its first handshake.

buffers

Writable storage that remains valid until completion.

webcpp::cobalt::io::write

Writes the complete buffer through the corrected native SSL wrapper.

Synopsis

/* implementation-defined */
write(
    ssl::stream& stream,
    const_buffer_sequence const& buffers);

Description

The operation starts when awaited. A failed or cancelled handshake prevents application writes. The buffer storage must outlive completion. Cancellation preserves the transferred count and does not close the underlying stream.

Return Value

A lazy operation with completion signature void(error_code, size_t).

Parameters

Name Description

stream

SSL stream, or a STARTTLS stream before its first handshake.

buffers

Readable storage that remains valid until completion.

webcpp::cobalt::io::read

Retains Boost’s composed reads for native non-SSL stream types.

Synopsis

using boost::cobalt::io::read;

webcpp::cobalt::io::write

Retains Boost’s composed writes for native non-SSL stream types.

Synopsis

using boost::cobalt::io::write;

WEBCPP_COBALT_FOR

Iterates an asynchronous range with the selected coroutine backend.

Synopsis

Declared in <webcpp/cobalt/config.hpp>

#define WEBCPP_COBALT_FOR(Value, Expression)

Description

Include webcpp/cobalt/async_for.hpp before using this macro. The arguments follow Boost.Cobalt’s BOOST_COBALT_FOR syntax on every target.

Parameters

Name Description

Value

The declaration receiving each yielded value.

Expression

The asynchronous range expression.

WEBCPP_COBALT_HAS_BROWSER_BRIDGE

1 when JavaScript Promises and events can be awaited through the Asio browser bridge.

Synopsis

Declared in <webcpp/cobalt/config.hpp>

#define WEBCPP_COBALT_HAS_BROWSER_BRIDGE

WEBCPP_COBALT_HAS_BROWSER_WORKERS

1 for an Emscripten pthread configuration; browser isolation and worker hosting are runtime requirements.

Synopsis

Declared in <webcpp/cobalt/config.hpp>

#define WEBCPP_COBALT_HAS_BROWSER_WORKERS

WEBCPP_COBALT_HAS_HOST_DNS

1 when the backend provides forward lookup; the host can still deny network or DNS capabilities.

Synopsis

Declared in <webcpp/cobalt/config.hpp>

#define WEBCPP_COBALT_HAS_HOST_DNS

WEBCPP_COBALT_HAS_LOCAL_SOCKETS

1 when native Boost.Asio supplies local sockets; WASI and browser transports do not impersonate Unix sockets.

Synopsis

Declared in <webcpp/cobalt/config.hpp>

#define WEBCPP_COBALT_HAS_LOCAL_SOCKETS

WEBCPP_COBALT_HAS_OPENSSL_BACKEND

1 when the target can link guest OpenSSL; select io_ssl or cobalt_ssl separately.

Synopsis

Declared in <webcpp/cobalt/config.hpp>

#define WEBCPP_COBALT_HAS_OPENSSL_BACKEND

WEBCPP_COBALT_HAS_PIPE_CREATION

1 when guest-created asynchronous pipes support transfer, cancellation and EOF.

Synopsis

Declared in <webcpp/cobalt/config.hpp>

#define WEBCPP_COBALT_HAS_PIPE_CREATION

WEBCPP_COBALT_HAS_POLLABLE_STDIO

1 when Asio’s explicit WASIp2 pollable stdio adapter is available with Cobalt tokens.

Synopsis

Declared in <webcpp/cobalt/config.hpp>

#define WEBCPP_COBALT_HAS_POLLABLE_STDIO

WEBCPP_COBALT_HAS_POSIX_STDIO

1 when native POSIX stdio descriptors can participate in asynchronous stream operations.

Synopsis

Declared in <webcpp/cobalt/config.hpp>

#define WEBCPP_COBALT_HAS_POSIX_STDIO

WEBCPP_COBALT_HAS_REVERSE_DNS

1 when native reverse lookup is available; WASI address lookup is forward-only.

Synopsis

Declared in <webcpp/cobalt/config.hpp>

#define WEBCPP_COBALT_HAS_REVERSE_DNS

WEBCPP_COBALT_HAS_SERIAL_PORT

1 when the native backend supplies serial ports; a browser or WASI host adapter is a separate facility.

Synopsis

Declared in <webcpp/cobalt/config.hpp>

#define WEBCPP_COBALT_HAS_SERIAL_PORT

WEBCPP_COBALT_HAS_SIGNALS

1 when native process-signal delivery is available; application cancellation remains available elsewhere.

Synopsis

Declared in <webcpp/cobalt/config.hpp>

#define WEBCPP_COBALT_HAS_SIGNALS

WEBCPP_COBALT_HAS_SOCKET_BACKEND

1 when the configured Asio backend provides native or WASI TCP/UDP; host grants remain runtime requirements.

Synopsis

Declared in <webcpp/cobalt/config.hpp>

#define WEBCPP_COBALT_HAS_SOCKET_BACKEND

WEBCPP_COBALT_HAS_THREADS

1 when the configured executor supports threads; WASIp3 cooperative threads are not CPU parallelism.

Synopsis

Declared in <webcpp/cobalt/config.hpp>

#define WEBCPP_COBALT_HAS_THREADS

WEBCPP_COBALT_NO_EXCEPTIONS

Defined when WebCPP’s Cobalt adapters are configured without exceptions.

Synopsis

Declared in <webcpp/cobalt/config.hpp>

#define WEBCPP_COBALT_NO_EXCEPTIONS

Description

The compiler and B2 exception-handling setting still determine the exception ABI of Boost.Cobalt and its compiled sources. This macro does not repair the pending-task move limitation in Boost.Cobalt issue 287 or change Boost APIs. Define WEBCPP_NO_EXCEPTIONS to select the policy for the whole collection, or this macro to select it for this integration alone.

See Also

"Exceptions and errors", in the guide.

Appendix A: Differences

On native targets, task, promise, generator, completion tokens and plain I/O types are Boost.Cobalt types. The upstream native implementation and runner sources remain byte-identical. One WebCPP translation unit checks the Boost version while compiling the core; it adds no runtime behavior. This preserves native interoperability; it also preserves upstream limitations outside the separately corrected SSL wrapper.

With Boost 1.92, the native limitation probes cover cancellation not reaching composed accept or composed waits. Further native checks reproduced with cleanup instantiation failures and a write_at constraint expecting write_op instead of write_at_op. Apple Clang 21 also diagnoses the original main and thread promises’ missing unhandled_exception members when compiling without exceptions; with warnings treated as errors, that consumer fails to compile. MSVC rejects the no-exceptions co_main with error C2039 for the same missing member; the limitation probes preserve a control with exceptions enabled and verify the promise shape. These are not new native guarantees supplied by WebCPP. The Wasm implementation carries its documented corrections, including the positioned-write constraint.

GCC 15.2 has a compiler regression for await_suspend with additional default arguments, including Cobalt’s race. It can fail with an internal compiler error in make_decl_rtl even in a program using only Boost.Cobalt. Use GCC 15.3 or a compiler containing the fix for GCC PR121643. The CI provisions GCC 15.3 and verifies this coroutine pattern before the suite; it does not patch the native Cobalt headers or skip the affected applications.

GCC 14 can emit -Wmismatched-new-delete for the upstream coroutine frame allocator. The maintainer identifies this as a false positive in Boost.Cobalt issue 7. Strict builds that promote this warning to an error fail even though allocation and release use the same stored memory resource. This compiler diagnostic is distinct from the no-exceptions runtime limitation in issue 287. WebCPP does not change native allocation or export a warning suppression to consumers. For an affected strict build, scope the diagnostic adjustment to the coroutine functions or translation units that reproduce it, rather than disabling allocation diagnostics globally.

The original io::udp_v6 constant also selects ICMP rather than UDP. Native identity preserves that defect. Use an explicit static protocol with the same IPv6 family and datagram type but the UDP protocol value; the udp_v6 regression records the original mismatch and exchanges datagrams with that control. The shipped Wasm backend corrects io::udp_v6 itself.

After the final writer closes a native Windows pipe, Boost.Asio reports broken_pipe rather than eof on the next empty read. The native Cobalt pipe retains that error and returns zero bytes. See Asio issue 1442. Native POSIX and WASIp3 tests require eof; none of these paths rewrites the native error.

WebCPP fixes Boost.Cobalt 1.92 SSL wrapper defects on native and WASIp2/P3. The owner approved this native exception on 2026-11-06 and retained it on 2026-11-07. webcpp::cobalt::io::ssl::stream is a distinct, corrected type; its native SSL context and plain Asio dependencies retain Boost identity. These are Cobalt wrapper fixes, not changes to OpenSSL’s cryptographic implementation or to native Cobalt’s core and runner.

The original handshake completion did not update the stream’s TLS state. Consequently, a successful handshake could leave secure() false, subsequent I/O selecting plain TCP and shutdown() returning no_protocol_option. Lazy handshake/shutdown operations also captured state at construction instead of checking it when awaited. The fix updates the stream before resuming the coroutine and checks its current state when an operation starts.

The original wrapper also allowed application I/O to select plain TCP after a failed or cancelled handshake. The fix records the first TLS attempt and blocks that fallback with not_connected and zero transferred bytes. Shutdown completion clears the TLS state even on error or cancellation. The precise state and retry contract is in SSL handshake and stream state; successful negotiation still does not replace the application’s trust and hostname verification settings.

Native complete-buffer SSL read/write overloads also fix lost cancellation by using Asio’s composed operations with the completion handler’s associated properties. This correction requires the concrete SSL type as explained in Preserve the corrected native SSL composition. Erasing it to Boost’s generic I/O stream still selects the unchanged upstream composition.

Move construction rebinds socket access to the destination’s SSL lowest layer and preserves handshake state, fixing the socket facade’s reference to the moved-from object. Copying and assignment are unavailable. Move only when no lazy or outstanding operation retains either stream’s address; moving does not transfer those operation references. After moving, the source is non-secure and may be destroyed. Tests destroy the source before handshake and after completed successful or rejected handshakes, then exercise the destination.

The TLS 1.2/1.3 regression fixtures are test/tls/cobalt_ssl_client.cpp, cobalt_ssl_state.cpp and cobalt_ssl_cancel.cpp: they check real peers, state transitions, blocked application I/O, moves, transfer cancellation and shutdown. The native identity fixtures check both header orders. See Testing for the lanes and their exception/threading profiles. These wrapper fixes do not repair the other native Boost limitations described above.

On Wasm, library-owned headers and sources select the same shipped Asio backend as WebCPP Beast. Corrections include the browser runner, WASI networking and SSL state machine, and aligned storage handling. The importer verifies original and corrected inputs and output hashes; application builds do not execute it. See upstream/README.md and its manifests for provenance.

In the browser, the runner and the checked task runner yield between bounded turns, with Asio’s default of 100 handlers. A long-running individual handler still blocks its thread. JSPI delegates suspension to the engine; Asyncify uses instrumented Wasm. Availability, stack requirements and performance are separate from Cobalt’s coroutine semantics.

An upstream example depending on a native signal, Unix socket, filesystem, blocking thread or TCP listener may require an explicit host counterpart. The matrix identifies that adaptation instead of promising identical facilities in a browser. A browser WebSocket or fetch operation uses host TLS and security policy rather than the guest OpenSSL wrapper.

Appendix B: Changelog

Changes prepared for WebCPP’s independent Cobalt integration.

Unreleased

  • Changed the SPSC demo to report inherited queue data loss.

  • Fixed finite echo cancellation and synchronized peer-reset verification.

  • Added a bounded SDK witness for unsupported Emscripten pipe EOF behavior.

  • Fixed GCC 14 coroutine allocation false positives blocking native test consumers.

  • Added explicit native and WebAssembly coroutine sources for independent consumers.

  • Fixed native/WASI SSL state and plaintext fallback after failed or cancelled handshakes.

  • Fixed SSL transfer cancellation and socket ownership after moving streams.

  • Fixed the shipped Wasm IPv6 UDP protocol constant; native Boost behavior remains documented.

  • Added target configuration, application matrices and Release performance and memory documentation.