Skip to content

Native Swift SDK exploration + Phase 0: pin the conformance seam - #225

Merged
crs48 merged 6 commits into
mainfrom
claude/swift-sdk-phase0
Jun 21, 2026
Merged

Native Swift SDK exploration + Phase 0: pin the conformance seam#225
crs48 merged 6 commits into
mainfrom
claude/swift-sdk-phase0

Conversation

@crs48

@crs48 crs48 commented Jun 21, 2026

Copy link
Copy Markdown
Owner

What & why

Explores making XNet a first-class citizen of native Apple development (and, long-term, Kotlin/.NET/C++), then implements Phase 0 — "pin the seam", the foundation every later phase depends on.

The exploration (0210) maps the kernel↔runtime fault line, surveys prior art (Automerge+UniFFI, Ditto, PowerSync, yrs), and recommends a phased dual-track: ship Swift fast on an embedded JavaScriptCore engine behind a native Swift API, then extract a Rust xnet-core kernel via UniFFI. Users write only Swift; the shared engine is swappable because the seam is the conformance-pinned protocol.

Phases 1–3 (the JSC engine, the Rust core, multi-language fan-out) are large, multi-quarter efforts and remain open. This PR delivers the self-contained, fully-verifiable Phase 0.

What's implemented (Phase 0)

  • L2 replication golden vectors (conformance/vectors/replication/) — version-handshake negotiation, the umbrella version bundle, node-sync catch-up filtering, and the byte-exact signed Yjs envelope (Ed25519 over BLAKE3(update ++ utf8(JSON(meta))), with meta in declaration order — a cross-language landmine now spec'd in L2 §4).
  • L3 authorization golden vectors (conformance/vectors/authz/) — authorization expression-AST evaluation (allow/deny/and/or/not/roleRef/PUBLIC/AUTHENTICATED + the and(allow,not(deny)) deny-wins composition).
  • All generated and drift-guarded in CI by the existing packages/runtime/src/conformance.test.ts (now 24 vectors, L0–L3).
  • Swift reference kernel (conformance/reference/swift/) — the Apple-platform sibling of the Python kernel. An independent Swift implementation reproduces the same did:key, canonical JSON, and BLAKE3 hashes and verifies TS-signed changes: 18/18 checks pass on Swift 6.3 (CryptoKit + nixberg/blake3-swift, base58/canonical-JSON inline).
  • Spec updates — L2/L3 vector pointers; the envelope insertion-order rule; an L3 note distinguishing the pinned AST core from fuller decision traces.

A real finding

The Swift kernel surfaced a concrete Apple-platform constraint that validates the exploration's "crypto gaps on Apple" risk: CryptoKit's Ed25519 is randomized — it verifies TS signatures correctly but cannot reproduce them byte-for-byte. Documented in the Swift README and the exploration's risks.

Verification

  • pnpm exec vitest run --project runtime packages/runtime/src/conformance.test.ts24 passed.
  • cd conformance/reference/swift && swift run VerifyVectors18 passed, 0 failed.
  • pnpm turbo run typecheck --filter=@xnetjs/runtime → green.
  • eslint + prettier clean on the changed TS; changelog fragment validates.

🤖 Generated with Claude Code

xNet Test and others added 4 commits June 20, 2026 16:10
…ge core

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Extends the protocol conformance corpus beyond the L0+L1 interop kernel:
- replication/ (L2): version-handshake negotiation, the umbrella version
  bundle, node-sync catch-up filtering, and the byte-exact signed Yjs
  envelope (Ed25519 over BLAKE3(update ++ utf8(JSON(meta))), meta in
  declaration order — the cross-language landmine, now spec'd).
- authz/ (L3): authorization expression-AST evaluation (allow/deny/and/or/
  not/roleRef/PUBLIC/AUTHENTICATED + the and(allow,not(deny)) deny-wins
  composition), mirroring evaluator.ts.

Generated and drift-guarded by the existing runtime conformance.test.ts
(now 24 vectors). Spec pointers + the envelope insertion-order rule added to
L2/L3. Part of exploration 0210 (native Swift SDK / portable core), Phase 0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A runnable Swift sibling of the Python reference kernel (the Apple-platform
proof for exploration 0210, Phase 0). Independently derives the same did:key,
canonical JSON, and BLAKE3 change hash, and verifies TypeScript-signed
changes — 18/18 checks pass (Swift 6.3, macOS). CryptoKit for Ed25519, the
pure-Swift nixberg/blake3-swift for BLAKE3, base58btc + canonical JSON inline.

Surfaces a concrete Apple-platform finding: CryptoKit's Ed25519 uses
randomized nonces, so it verifies TS signatures but does NOT re-sign them
byte-for-byte (validates the 'crypto gaps on Apple' risk in 0210). Reference
material, not in CI (like the Python kernel).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Marks the 'pin the seam' phase done in the exploration's checklists (L2/L3
vectors, Swift reference kernel, canonical-JSON/envelope spec, CI drift
guard) and adds the changelog fragment. Phases 1-3 (Swift JSC engine, Rust
xnet-core, multi-language fan-out) remain open.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@crs48
crs48 temporarily deployed to pr-225 June 21, 2026 02:00 — with GitHub Actions Inactive
@crs48
crs48 temporarily deployed to pr-225 June 21, 2026 02:02 — with GitHub Actions Inactive
github-actions Bot added a commit that referenced this pull request Jun 21, 2026
@github-actions

github-actions Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Preview removed for PR #225.

@crs48
crs48 temporarily deployed to pr-225 June 21, 2026 18:29 — with GitHub Actions Inactive
github-actions Bot added a commit that referenced this pull request Jun 21, 2026
@crs48
crs48 merged commit 2994722 into main Jun 21, 2026
11 checks passed
@crs48
crs48 deleted the claude/swift-sdk-phase0 branch June 21, 2026 18:35
github-actions Bot added a commit that referenced this pull request Jun 21, 2026
crs48 added a commit that referenced this pull request Jun 21, 2026
…227)

## What & why

Completes the user-facing vision of [exploration
0210](docs/explorations/0210_[_]_NATIVE_SWIFT_SDK_AND_PORTABLE_MULTI_LANGUAGE_CORE.md):
**a real, runnable native Swift SDK** where you *define schemas in
Swift, write and query the database in Swift, and bind results into a
SwiftUI re-rendering loop* — no JavaScript, no React.

It builds directly on the conformance-pinned protocol kernel landed in
[#225](#225), so identity (`did:key`),
canonical change hashes, and per-property LWW convergence match the
TypeScript reference. `swift run xnet-demo` runs it end-to-end; **14
tests pass** including the shared golden vectors.

## What's in `swift/XNetKit/`

| Layer | File |
| --- | --- |
| Schema DSL (`Schema { text(…); select(…) }` → `SchemaIRI`) |
`Schema.swift` |
| Signed change log + per-property LWW materialization | `Change.swift`,
`Node.swift`, `NodeStore.swift` |
| `Sendable` `Predicate` + fluent `Query` | `Query.swift` |
| `liveQuery` subscribe contract + `@Observable LiveQueryModel` |
`LiveQuery.swift` |
| `did:key` + Ed25519 (CryptoKit), BLAKE3, canonical JSON |
`Identity/Crypto/JSONValue.swift` |
| End-to-end demo | `Sources/xnet-demo/main.swift` |

```swift
let Task = Schema(name: "Task", namespace: "xnet://xnet.fyi/") {
    text("title", required: true); select("status", options: ["todo","doing","done"], default: "todo")
}
let store = NodeStore(identity: Identity())
let t = store.create(Task, ["title": "Ship it", "status": "todo"])
let todo = store.query(Query(Task, where: .equals("status", "todo")).ordered(by: "title"))
// SwiftUI: List(LiveQueryModel(store, Query(Task)).rows) { Text($0["title"]?.stringValue ?? "") }
```

## Hardened by an adversarial review

A multi-agent review found **6 confirmed issues, all fixed and locked
with tests**:
1. Object keys now sort by **UTF-16 code unit** (matched JS; Swift's
default scalar sort diverges for astral-plane keys).
2. **Integer-valued doubles** serialize like JS (`10000000000000000`,
not `1e+16`).
3. `JSONValue.compare` now handles doubles/bools/mixed numerics (was
silently `.orderedSame`).
4. `schemaId`/`createdAt` resolved **order-independently**
(earliest-by-lamport), not by append order.
5. `@Observable` `rows` mutation wrapped in `MainActor.assumeIsolated`.
6. Dropped an **unsound `Cancellable: Sendable`** and the
cross-isolation `AsyncStream` teardown.

## Scope (honest status)

This is the **native-authoring slice**. It took the *native-runtime*
route rather than the exploration's recommended JSC-embedded engine —
trading 100% TS parity for a pure-Swift, dependency-light core. **Not
yet included** (tracked in the exploration's checklists): live hub sync
(`URLSessionWebSocketTask`), persistent storage (GRDB/SQLite), E2E
encryption (libsodium XChaCha20), Keychain identity custody, full
client-side authz enforcement, and Swift-6 strict-concurrency (`actor`
store). One Apple constraint surfaced earlier holds: CryptoKit Ed25519
is randomized (verifies but doesn't re-sign byte-for-byte).

## Verification

- `cd swift/XNetKit && swift test` → **14 passed** (conformance + store
+ live-query + canonicalization).
- `swift run xnet-demo` → identity → schema → signed writes → query → 5
reactive renders → LWW convergence.
- The package lives at top-level `swift/` (outside the pnpm workspace),
so it doesn't touch TS CI; changelog fragment included.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant