stdb: drop the v1 JSON wire, and ship it as 4.0.0 #110
No reviewers
Labels
No labels
area:defold
area:docs
area:infra
area:protocol
area:testing
kind:bug
kind:chore
phase:breadth
phase:core
phase:hardening
phase:slice
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
yuris/spacetimedb-defold!110
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "remove-v1-wire"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes the last thing making this SDK structurally different from every official one: it spoke two wires.
Why
SpacetimeDB 2.x serves the v1 message schema on
v1.json.spacetimedband the v2 schema only onv2.bsatn.spacetimedb(crates/client-api/src/routes/subscribe.rsmapsTEXT_PROTOCOL→WsVersion::V1). Upstream already decided what to do about that:sdks/rust/src/websocket.rs:250,371sdks/csharp/src/SpacetimeDBClient.cs:226sdks/unreal/.../Websocket.cpp:52spacetime subscribecrates/cli/src/subcommands/subscribe.rs:254None of them keeps v1 selectable — no negotiation, no fallback, and the v2 types are welded into their signatures. Grepping
sdks/csharp/srcandsdks/unreal/srcfor any v1 identifier returns nothing.This SDK was the only client carrying both, and it paid for it with a second implementation of every send path, a parallel handler table, and a 1215-line JSON codec shipped to every consumer inside
include_dirs = stdb.stdb/loses 1710 lines (−20%).Removed — all of it already unreachable on the default wire
db:subscribe, the legacy whole-set form. Not a judgement call: the v2ClientMessagehas no legacySubscribe— itsSubscribeis the query-set form — so there was no frame to send and the call has raised since 2.0.0.subscribe_query,subscription_builderandunsubscribeare untouched.c.subscriptionsand thesubscription_replacedevent (which reported #43's hold-count drift) go with it.opts.protocol,opts.light,Builder:with_protocol,SUBPROTOCOL_V2.lightwas v1-only and already raised on v2.opts.jsononconnect/connection.new— it only ever fed the JSON codec.auth.exchangeandschema.fetchstill take one, being HTTP. Its process-global codec guard goes too: that hazard existed only becausestdb/protocol.luaheld one codec per process.Call:on_out_of_energy.ReducerOutcomehas noOutOfEnergyvariant, so nothing could set that state any more — it registered a callback that could never fire, which reads as working. Exhaustion arrives asInternalErrortext and reacheson_error.cache.lua's untyped decode path.row_decoderis always installed now, soundecodablerejects a relation with notypesbefore any decoder runs; the fallback was dead code.one_off_key— v1 correlated on an echoed hexmessage_id; v2 correlates onrequest_id.Kept, and why
stdb/protocol.lua→dev/test/crosscheck_v1.lua, decode half only. Not part of the SDK; nothing understdb/requires it, and nothing ships it.It survives because BSATN is opaque.
03 00 00 00is a valid u32, half a u64, or a length prefix, and only the decoder's belief about the type decides — so a wrong belief returns a plausible number instead of raising, and in Lua nothing catches that.test_protocol_v2.luadecodes frame 29 of the captured session both ways and asserts the two Lua values are equal. The decoders share no code and were written from different upstream sources, so agreement is evidence rather than tautology.Verified by mutation, not assertion:
protocol_v2.luau64reader →u32test_protocol_v2,test_slicing,test_tables,test_connection_handlestest_protocol_v2,test_connection_handlesThe second failure is named "identity rendered big-endian, matching identity_to_hex" —
identity_to_hexiscrosscheck_v1's own function. That is the cross-check doing the job it was kept for.The v1 client encoder was deleted with the wire: an encoder has no second implementation to disagree with, so it was only ever testing itself.
New seam
connection.dispatch(c, msg), split out ofhandle_frame, which is now decode + dispatch. Decoding bytes and acting on a message are two jobs, and everything below that line is bookkeeping that does not care how the bytes arrived. There is no server-side BSATN encoder in this repo, so without the split the connection tests could not exist at all — they would have to hand-assemble every server frame.Tests
2119 → 2078 assertions, ~25 of them new (
connection_id_to_hexafter its move and signature narrowing, the gzip URL case from #107, procedure-return decode failure). Every deletion covered behaviour that no longer exists.test_connection.luawas jammed against Lua 5.1's hard 200-local-per-function ceiling — its own comments were already working around it withdoblocks and nested functions — so it splits intotest_connection.lua,test_connection_handles.lua, and a sharedconn_fixtures.lua.Cache and fixture tests install
crosscheck_v1ascache.row_decoder, keeping their readable JSON rows rather than re-encoding 47 fixtures to BSATN. Those files test the cache, not a codec.Version
4.0.0. Public surface is gone, which matches the precedent of 2.0.0 — that bumped major for a default change alone. No migration guide: the install URL is a version-pinned zip so nobody on 3.x is disturbed, and #105 already set that precedent.Not verified locally
The live conformance harness needs a real SpacetimeDB server and the Defold engine, so CI is what exercises it here. Syntax is clean (
luac -p,bash -n,node --check).PHASE8's claim was rewritten rather than dropped: it used to prove the v1 light-mode cross-client asymmetry, and now proves the v2-native equivalent — a broadcast
TransactionUpdatecarries norequest_idat all, structurally distinct from the caller's ownReducerResult::Ok. Sound againstconnection.lua, but only a live run proves it.Wiki
Handled separately — the wiki is its own git repo, so it cannot ride in this PR.
V1-Opt-Outgoes away entirely;Usage-Guide,API-Reference,Protocol-Notes,Roadmap,Quickstart,Installation,DevelopmentandHomeall carry v1 references that follow this change.SpacetimeDB 2.x serves the v1 message schema on `v1.json.spacetimedb` and the v2 schema only on `v2.bsatn.spacetimedb`. Every official SDK deleted v1 outright rather than keeping it selectable: the Rust, C# and Unreal SDKs hardcode `v2.bsatn.spacetimedb` with no negotiation and no fallback, and the v2 types are welded into their signatures. This SDK was the only client still carrying both, and carrying it cost a second implementation of every send path, a parallel handler table, and a JSON codec shipped to every consumer inside `include_dirs = stdb`. So the wire is v2 and only v2. stdb/ loses 1710 lines. REMOVED, ALL OF IT UNREACHABLE ON THE DEFAULT WIRE ALREADY: * `db:subscribe` - the legacy whole-set form. Not a judgement call: the v2 ClientMessage has no legacy Subscribe, its Subscribe IS the query-set form, so there was no frame to send and the call has raised since 2.0.0. `subscribe_query`, `subscription_builder` and `unsubscribe` are untouched. With it go `c.subscriptions` and the `subscription_replaced` event that reported #43's hold-count drift. * `opts.protocol`, `opts.light`, `Builder:with_protocol`, `SUBPROTOCOL_V2`. `light` was v1-only and already raised on v2. * `opts.json` on `connect`/`connection.new`. It only ever fed the JSON codec; `auth.exchange` and `schema.fetch` still take one, being HTTP. Its process-global codec guard goes too - that hazard existed only because stdb/protocol.lua held one codec per process. * `Call:on_out_of_energy`. ReducerOutcome has no OutOfEnergy variant, so nothing could set that state any more: it registered a callback that could never fire, which reads as working. Exhaustion arrives as InternalError text and reaches `on_error`. * cache.lua's untyped decode path. `row_decoder` is always installed now, so `undecodable` rejects a relation with no `types` before any decoder runs and the fallback was dead. * `one_off_key` - v1 correlated on an echoed hex message_id; v2 correlates on request_id. SPLIT, NOT DELETED: stdb/protocol.lua -> dev/test/crosscheck_v1.lua, decode half only. It is not part of the SDK and nothing under stdb/ requires it. It stays because BSATN is opaque - `03 00 00 00` is a valid u32, half a u64, or a length prefix, and only the decoder's belief decides, so a wrong belief returns a plausible number instead of raising. test_protocol_v2.lua decodes frame 29 of the captured session both ways and asserts the two Lua values are equal; the decoders share no code and were written from different upstream sources, so agreement is evidence. Mutating the BSATN identity byte order or its u64 reader fails that differential - verified both ways. The v1 client ENCODER was deleted with the wire: an encoder has no second implementation to disagree with. NEW SEAM: `connection.dispatch(c, msg)`, split out of `handle_frame`, which is now decode + dispatch. Decoding bytes and acting on a message are two jobs, and everything below that line is bookkeeping that does not care how the bytes arrived. There is no server-side BSATN encoder in this repo, so without the split the connection tests could not exist at all. TESTS: 2119 -> 2078 assertions, ~25 of them new. Every deletion covered behaviour that no longer exists. test_connection.lua was jammed against Lua 5.1's 200-local ceiling - its own comments were already working around it - so it splits into test_connection.lua, test_connection_handles.lua and a shared conn_fixtures.lua. Cache and fixture tests install crosscheck_v1 as `cache.row_decoder`, keeping readable JSON rows: those files test the cache, not a codec. 4.0.0 rather than 4.x because public surface is gone, matching the precedent of 2.0.0, which bumped major for a default change alone. No migration guide: the install URL is a version-pinned zip, so nobody on 3.x is disturbed, and #105 already set that precedent. Not verified here: the live conformance harness needs a real server and the Defold engine. PHASE8's claim was rewritten from the v1 light-mode cross-client asymmetry to its v2-native equivalent - a broadcast TransactionUpdate carries no request_id at all, unlike ReducerResult::Ok.bf30c06dba866cbe16e7