oficina / docs Public

Plan 1: the Rust core runs under wazero, wire-compatible with browser Yjs

A Rust y-crdt crate compiles to plain wasm32-unknown-unknown with a C ABI
and zero imports, runs under wazero inside a cgo-free Go binary with no
JavaScript host anywhere, and stays byte-compatible with browser yjs in
both directions including formatting. The branch was allowed to conclude
the architecture was wrong. It does not.

Seven tasks: the Rust crate; a Node fixture generator using real yjs; both
compatibility directions with the fixtures as a contract; the C ABI; the
Go wazero host; and .amadan/ci.d/10-gate. Plus the spec commits recording
what execution discovered.

What the design did not anticipate:

yrs calls std::str::from_utf8_unchecked on wire data (read.rs:137). A
mutation fuzz hit it on 0.4-5.1% of single-byte corruptions of our own
fixtures -- random bytes are harmless, which is why a naive garbage-input
test proves nothing. Not fixable from our layer; contained by the
per-document wasm instance, and still to file upstream. That makes the
sandbox load-bearing for security rather than only portability: inside
wasm the fault is a contained trap where a native build corrupts silently.

But the containment claim needed correcting, and the branch's own tests
said so: some corrupted updates are silently ACCEPTED, so downstream must
not assume document text is valid UTF-8.

And a 36-byte corrupted fixture ran apply for 163 real seconds and
returned the correct answer -- denial of service invisible to any
correctness test. The host now caps execution at 1s; the original 5s never
fired for the input it was added for.

This is falsification-grade, not production-grade, and says so. ABI v1 has
no state export, so trap recovery is capped log replay rather than
snapshot restore, and the 4096-update cap would make a longer-lived
document unloadable. Blocking before internal/core gets a real caller.

Every gate here started out checking something adjacent to its purpose and
was corrected: the zero-imports test passed by skipping, the trap test
passed against a host that never discarded, the containment fuzz checked
liveness while discarding the bytes it compared. A check that reports
success without checking is the most repeated finding of this work.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011F5CivVm4CmL9ByfSSAaXA
Paul Campbell pushed by paul@keymail.dev 65a2396ebc74c975bfd11c6ccb7b56463dafb117 parent 878690a
50 files changed, +7252 −42
  • .amadan/README.md +49 −0
  • .amadan/ci.d/10-gate +73 −0
  • .cargo/config.toml +19 −0
  • .gitignore +3 −0
  • AGENTS.md +17 −2
  • clippy.toml +5 −0
  • core/.gitignore +1 −0
  • core/Cargo.lock +583 −0
  • core/Cargo.toml +33 −0
  • core/src/abi.rs +288 −0
  • core/src/bin/emit_update.rs +29 −0
  • core/src/lib.rs +110 −0
  • core/tests/no_host_imports.rs +56 −0
  • core/tests/wasm_trap_containment.rs +624 −0
  • core/tests/wire_compat.rs +191 −0
  • core/vendor/README.md +120 −0
  • core/vendor/fastrand-2.5.0/CHANGELOG.md +140 −0
  • core/vendor/fastrand-2.5.0/Cargo.toml +96 −0
  • core/vendor/fastrand-2.5.0/LICENSE-APACHE +201 −0
  • core/vendor/fastrand-2.5.0/LICENSE-MIT +23 −0
  • core/vendor/fastrand-2.5.0/README.md +110 −0
  • core/vendor/fastrand-2.5.0/benches/bench.rs +141 −0
  • core/vendor/fastrand-2.5.0/src/global_rng.rs +234 −0
  • core/vendor/fastrand-2.5.0/src/lib.rs +736 −0
  • core/vendor/fastrand-2.5.0/tests/char.rs +44 −0
  • core/vendor/fastrand-2.5.0/tests/smoke.rs +357 −0
  • docs/superpowers/plans/2026-08-30-rust-core-wire-compat.md +1340 −0
  • docs/superpowers/specs/2026-08-30-docs-design.md +259 −40
  • fixtures/.gitignore +1 −0
  • fixtures/data/concurrent.expected.json +8 −0
  • fixtures/data/concurrent.update.bin binary
  • fixtures/data/formatted.expected.json +17 −0
  • fixtures/data/formatted.update.bin binary
  • fixtures/data/hello.expected.json +8 −0
  • fixtures/data/hello.update.bin binary
  • fixtures/data/unicode.expected.json +8 −0
  • fixtures/data/unicode.update.bin binary
  • fixtures/generate.mjs +66 −0
  • fixtures/package-lock.json +61 −0
  • fixtures/package.json +9 −0
  • fixtures/verify-rust.mjs +42 −0
  • go.mod +7 −0
  • go.sum +4 −0
  • internal/core/core.go +524 −0
  • internal/core/core_internal_test.go +441 −0
  • internal/core/core_test.go +104 −0
  • internal/core/testdata/docs_core.wasm binary
  • rust-toolchain.toml +4 −0
  • scripts/build-wasm.sh +43 −0
  • scripts/wire-gate.sh +23 −0

CI passed — run details

.amadan/README.md

Loading diff…

.amadan/ci.d/10-gate

Loading diff…

.cargo/config.toml

Loading diff…

.gitignore

Loading diff…

AGENTS.md

Loading diff…

clippy.toml

Loading diff…

core/.gitignore

Loading diff…

core/Cargo.lock

Loading diff…

core/Cargo.toml

Loading diff…

core/src/abi.rs

Loading diff…

core/src/bin/emit_update.rs

Loading diff…

core/src/lib.rs

Loading diff…

core/tests/no_host_imports.rs

Loading diff…

core/tests/wasm_trap_containment.rs

Loading diff…

core/tests/wire_compat.rs

Loading diff…

core/vendor/README.md

Loading diff…

core/vendor/fastrand-2.5.0/CHANGELOG.md

Loading diff…

core/vendor/fastrand-2.5.0/Cargo.toml

Loading diff…

core/vendor/fastrand-2.5.0/LICENSE-APACHE

Loading diff…

core/vendor/fastrand-2.5.0/LICENSE-MIT

Loading diff…

core/vendor/fastrand-2.5.0/README.md

Loading diff…

core/vendor/fastrand-2.5.0/benches/bench.rs

Loading diff…

core/vendor/fastrand-2.5.0/src/global_rng.rs

Loading diff…

core/vendor/fastrand-2.5.0/src/lib.rs

Loading diff…

core/vendor/fastrand-2.5.0/tests/char.rs

Loading diff…

core/vendor/fastrand-2.5.0/tests/smoke.rs

Loading diff…

docs/superpowers/plans/2026-08-30-rust-core-wire-compat.md

Loading diff…

docs/superpowers/specs/2026-08-30-docs-design.md

Loading diff…

fixtures/.gitignore

Loading diff…

fixtures/data/concurrent.expected.json

Loading diff…

fixtures/data/concurrent.update.bin

Loading diff…

fixtures/data/formatted.expected.json

Loading diff…

fixtures/data/formatted.update.bin

Loading diff…

fixtures/data/hello.expected.json

Loading diff…

fixtures/data/hello.update.bin

Loading diff…

fixtures/data/unicode.expected.json

Loading diff…

fixtures/data/unicode.update.bin

Loading diff…

fixtures/generate.mjs

Loading diff…

fixtures/package-lock.json

Loading diff…

fixtures/package.json

Loading diff…

fixtures/verify-rust.mjs

Loading diff…

go.mod

Loading diff…

go.sum

Loading diff…

internal/core/core.go

Loading diff…

internal/core/core_internal_test.go

Loading diff…

internal/core/core_test.go

Loading diff…

internal/core/testdata/docs_core.wasm

Loading diff…

rust-toolchain.toml

Loading diff…

scripts/build-wasm.sh

Loading diff…

scripts/wire-gate.sh

Loading diff…