oficina / docs Public

Plan: Task 3 compares deltas, not just plain text

Ruling R5, carried into the plan. The fixtures gained a delta field
because text alone cannot tell a correct implementation from one that
decoded the update and dropped the formatting -- and nothing else in the
plan caught that either, so a plan whose whole purpose is proving wire
compatibility could not see the loss of bold, italics or links.

Carries the verified yrs API facts so the implementer builds against
checked signatures rather than guessing, and requires the assertion be
proven to bite by temporarily discarding attributes -- same discipline
as the zero-imports gate, which turned out to be worth having.
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 fad6a875a654fb3d72fd9b5536c4846388e2d7a6 parent 95f167a
1 file changed, +33 −5
  • docs/superpowers/plans/2026-08-30-rust-core-wire-compat.md +33 −5
diff --git a/docs/superpowers/plans/2026-08-30-rust-core-wire-compat.md b/docs/superpowers/plans/2026-08-30-rust-core-wire-compat.md
index 4673ab1..bb2a90d 100644
--- a/docs/superpowers/plans/2026-08-30-rust-core-wire-compat.md
+++ b/docs/superpowers/plans/2026-08-30-rust-core-wire-compat.md
@@ -297,10 +297,11 @@ fn fixture(name: &str) -> (Vec<u8>, String) {
}
fn check(name: &str) {
- let (update, expected) = fixture(name);
- let doc = Doc::new();
+ let (update, expected_text, expected_delta) = fixture(name);
+ let doc = Doc::with_client_id(9001); // never Doc::new() — see Global Constraints
docs_core::apply_update(&doc, &update).expect("apply failed");
- assert_eq!(docs_core::text_content(&doc), expected, "fixture {name}");
+ assert_eq!(docs_core::text_content(&doc), expected_text, "fixture {name} text");
+ assert_eq!(delta_of(&doc), expected_delta, "fixture {name} delta");
}
#[test]
@@ -324,13 +325,40 @@ fn applies_concurrent() {
}
```
-Add the dev-dependency to `core/Cargo.toml`:
+Add the dev-dependency to `core/Cargo.toml` (exact pin, per Global Constraints):
```toml
[dev-dependencies]
-serde_json = "1"
+serde_json = "=1.0.145"
```
+Take whatever exact version `cargo add --dev serde_json` resolves.
+
+**The delta comparison — amended during execution (ruling R5).** The fixtures
+now carry a `delta` field alongside `text`, because `text` alone cannot
+distinguish a correct implementation from one that decoded the update and
+dropped the formatting entirely. `fixture()` must therefore return three
+values, and the test needs a `delta_of(&Doc)` helper that produces the same
+attributed-run shape Yjs's `toDelta()` writes.
+
+Verified API facts to build it from — check each against the pinned `yrs`
+rather than trusting this list:
+
+- `Text::diff<T, D, F>(&self, txn: &T, compute_ychange: F) -> Vec<Diff<D>>` —
+ `yrs-0.23.5 src/types/text.rs:420`, on the `Text` trait.
+- `Diff<T> { insert: Out, attributes: Option<Box<Attrs>>, ychange: Option<T> }`
+ — `text.rs:1103`.
+- `YChange::identity` — `text.rs:1201`, the pass-through for `compute_ychange`.
+- `Attrs = HashMap<Arc<str>, Any>` — `types/mod.rs:882`.
+
+Attribute order must be normalised (sort by key) before comparison, or the
+test is flaky on `HashMap` iteration order.
+
+**The delta assertion must be proven to bite**, the same way the zero-imports
+gate was: temporarily make `delta_of` discard attributes, confirm the
+`formatted` fixture fails and the other three still pass, then revert. A
+comparison that cannot fail is not an assertion.
+
- [ ] **Step 2: Run the test to verify it fails**
```bash