diff --git a/.changeset/storage-and-codegen-notes.md b/.changeset/storage-and-codegen-notes.md
new file mode 100644
index 0000000000..4b9ff11045
--- /dev/null
+++ b/.changeset/storage-and-codegen-notes.md
@@ -0,0 +1,5 @@
+---
+'zero-swift': patch
+---
+
+Documents that the main thread waits up to about 5 s when it opens a database another program holds locked, and up to about 10 s in `flush()` or `close()` on a busy one; that two generated schemas with a table of the same name need modules of their own; and that a flipped `whereExists` reaching a `limit` early, where JS asserts "Unexpected early return prevented full hydration", keeps working in Swift.
diff --git a/packages/zero-swift-cli/README.md b/packages/zero-swift-cli/README.md
index 8206c21c1f..a9f25da0e3 100644
--- a/packages/zero-swift-cli/README.md
+++ b/packages/zero-swift-cli/README.md
@@ -56,6 +56,11 @@ Rename a row struct whose name clashes with a type you use. A table named
`list` generates `struct List`, which hides SwiftUI's `List`; set
`tables.list.type` to `NoteList`, or set a `typePrefix`.
+Two generated schemas with a table of the same name can't share a module:
+both declare `tx.mutate.
`. Generate each into a module of its own.
+Code that imports both names the row type, as in
+`TypedTableMutator(tx.mutate).insert(…)`.
+
### Names
Tables, columns, relationships, JSON fields and enumeration values keep
diff --git a/swift/DESIGN.md b/swift/DESIGN.md
index 41a12e1892..def08aa1f8 100644
--- a/swift/DESIGN.md
+++ b/swift/DESIGN.md
@@ -219,10 +219,18 @@ Rationale:
- If the store can't be opened, the client runs on memory and calls
`onStorageFailure`, as JS does. A failed write stops writing and calls it
too. A write that finds the database busy is kept and written with the
- next one, or by `flush()` and `close()`, which try twice more before they
+ next one, or by `flush()` and `close()`, which try once more before they
call it a failure. Stored data that doesn't decode is lost client state,
as a corrupt ref count is in JS: the client deletes the database, starts
a new one, and calls `onClientStateNotFound` if the app set it.
+- These waits are on the main thread, each up to SQLite's 5 s busy
+ timeout. Opening a database another connection holds locked blocks
+ `Zero.init` for about 5 s before the client falls back to memory, and
+ `flush()` or `close()` on a busy database blocks for up to about 10 s:
+ the queued write, then the retry. With one process per store, only
+ another program with the file open, such as a SQLite browser, holds
+ such a lock. Opening and closing the store off the main actor would
+ avoid the waits; that is deferred.
- A client writes a poke's snapshot only when its cookie is newer than the
stored one, as Replicache persists, so a client of the group that is
behind another doesn't overwrite it.
diff --git a/swift/Sources/Zero/Zero.docc/JSParity.md b/swift/Sources/Zero/Zero.docc/JSParity.md
index 86c3524a43..0873affe40 100644
--- a/swift/Sources/Zero/Zero.docc/JSParity.md
+++ b/swift/Sources/Zero/Zero.docc/JSParity.md
@@ -163,6 +163,13 @@ is written or sent.
connection in the `error` state, a mutation that fails is committed and
its `client` outcome is the error, and later mutations, `materialize`,
and `run` fail with the same message.
+- **A flipped `whereExists` stopping a `limit` early.** To learn whether a
+ row a change brings has a match, a flipped `whereExists` reads its
+ subquery's first row only. When that read goes through a `limit` whose
+ rows for this row weren't read before, JS asserts ("Unexpected early
+ return prevented full hydration") and the change fails as above. Swift
+ keeps working and shows the rows JS shows once its `Take` reads the rest
+ of such a fetch, as the comment by that assertion proposes.
- **Nulls in columns that can't be null.** When the server sends null for
a column the schema says isn't optional, a `String`, `Double`, `Int`, or
`Bool` property reads as `""`, `0`, or `false`. JS hands the null