v1.1.0 release checklist #59
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#59
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
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?
v1.1.0 release checklist
Shipped:
v1.1.0=46b433e, published. Remaining unchecked items need themaintainer, not an agent.
v1.0.0 froze the public API. Everything here is additive or internal; the one
signature change (
backoff_delay) gained a trailing optional parameter, so nocallsite broke.
Worked the same way #24 was: one issue per unit of work, each through
branch → PR → independent review → actioner → merge, with reviewers instructed
to re-capture the wire rather than trust the author.
Phase 1 — harness first
$PORTso pidfiles and data cannot collide.
server_pid()verifies the recordedpid is our server for this port — by reading its argv, not by asking who
holds the port, after review found the
ss | grep -qversion returnedfailure on a match under
pipefail. Landed as #60.Phase 2 — independent, parallel
identity, NOT
math.random. Landed as #62. Review measured thedistribution and disproved two of the claims made for it.
neither outcome the issue anticipated:
sys.savedoes not sync, but theloader patches
FS.closeso every save starts one anyway. Landed as #61after three review rounds on factual accuracy.
Phase 3 — the headline feature
stdb/auth.luaplus the SDK's firsthttpseam. Landed as #64. Two blocking defects found first: a storage seam that
made the documented configuration silently useless, and a circular
requirethatbobrefuses to build.Phase 4 — measure before building
rows native, 100ms at ~31,000 (~9,800 on HTML5). Landed as #66.
Time-slicing is justified and is now #67.
was wrong by ~4.5× — the instrumentation had missed
quote_big_ints— andis retracted and corrected in place.
Phase 5 — release gate
before they froze, landed as #68
found ten wrong, all corrected
against the tag's own artifact plus a real consumer install
Needs the maintainer, not an agent
defold/extension-websocket— needs a GitHub account.The patch and its handshake evidence are paste-ready in
patches/.continue-on-erroronce weekly HTML5 runs have been green.Not automatable; it is a judgement on accumulated CI history — and #52 saw
a possible recurrence during this release gate, so the case for keeping it
has not weakened.
Opened by this milestone, deliberately not done
quote_big_intsis unguarded and costs ~40% of the apply frame. Thecheapest real optimisation found, and it should land before #67.
identity, so a fleet relaunching into an outage is not covered. Arguably the
more important herd.
STDB_STATE_DIRcan leak a server.Deliberately untouched
#52 — one unreproducible occurrence, six mechanisms already disproved and
recorded. A possible recurrence during this release gate is recorded there, with
the frame capture it asks for explicitly noted as missing.
Progress: phase 1 done, phase 2 half done
mainis atcf8b430, green end to end: unit 6/6, stylua 0, shellcheck 0,native conformance PASS, HTML5 conformance PASS.
Phase 1 — #54 merged (#60). Default state dir is now keyed on
$PORT, andserver_pid()identifies our server by reading/proc/$pid/cmdlinerather thanby asking who holds the port.
Both failures were reproduced on
mainbefore fixing, and review earned itskeep twice here. Round one found the first attempt BLOCKING:
ss -ltnp | grep -qunder
set -o pipefailreturns 141 for a pipeline that matched, becausegrep -qexits early andssdies of SIGPIPE — so a healthy server read asabsent. This script already documents that exact trap elsewhere. Round one also
disproved the justification I had written, that
sswas already used here; it wasnot, and the claim came from the plan and was repeated unchecked. Replacing the
mechanism with an argv read dissolved three of the five findings at once. Round
two then attacked the replacement specifically and cleared it.
Phase 2 — #19 merged (#62). Deterministic per-client spread, not
math.random. Live on the wire: conformance logsreconnecting attempt 1 in 0.608swheremainwas a flat1s.Review measured the distribution rather than trusting the two-sample example in
my PR body, and disproved two claims I had made:
there are exactly 1000 possible outputs, so 365 of 1000 clients collide, which
is precisely the birthday bound. Behaviourally fine (15ms apart at the cap, not
simultaneous); the sentence overreached.
the attempt seed, so the cohort is translated by one constant —
h(id,2)-h(id,1)measured as the single value 2807132593 across 400 realidentities, with 57% of colliding pairs still colliding at the next attempt.
Both corrected before merge, since phase 5's README-truth gate would have failed
them anyway.
Phase 2 — #20 open as #61, documentation only, in re-review. The engine-source
answer was neither of the two outcomes the issue anticipated:
sys.savedoes notsync, but the HTML5 loader patches
FS.closeso every save starts one anyway —so the proposed flush would be redundant, and deleting the caveat would erase a
real race. Review then disproved two of my own claims about the loader (the save
direction does not retry; the breaker can wedge persistence permanently), so the
text now names the silent-loss case outright.
Phase 3 — #31 open as #64, in review. Spike settled branch C: 2.8.2 has no
exchange endpoint (
/v1/identity/token,/v1/token,/v1/auth,/v1/identity/exchangeall 404) and only a single JWT keypair, no issuer or JWKSoption — so the exchange target is the game's own backend.
Phase 4 — #30 in progress, measurement running.
Filed along the way
STDB_STATE_DIRleak a server. Found inreview of #60; unreachable by default after it.
arguably the more important herd: #19 covers a server restart that drops live
sockets, but not an outage that makes the whole player base relaunch. The
identity is already on disk three lines above the callsite, but it is not
server-confirmed there, so spreading on it is a real judgement call rather than
an oversight.
Also recorded, not pursued: a malformed bearer token panics a tokio worker in
2.8.2 (
spacetimedb-jsonwebtoken-9.3.0/src/decoding.rs:199, "entered unreachablecode") and takes the server process down. Upstream, in a pinned dependency.
Progress: phases 1–4 done, phase 5 in flight
mainis at8d8bc2c. Four of the five milestone issues are merged and theframe-budget measurement has landed.
stdb/auth.lua,auth.exchange, the SDK's first HTTP seamPhase 4's answer
Time-slicing is justified: the 60fps budget is exceeded at ~6,100 rows native
and 100ms at ~31,000 (~9,800 on HTML5, where an idle wasm frame already costs
17ms to
requestAnimationFrame). All three swept across the crossing rather thanextrapolated. #67 carries the implementation, with the ordering property — a
TransactionUpdatearriving mid-batch must be applied after it, never interleaved— as its acceptance criterion.
The measurement corrected a conclusion I had already published
I posted a BSATN benchmark to #9 concluding the Amdahl ceiling was 1.8× native /
1.3× wasm. Review found the instrumentation stopped one function short:
quote_big_intswas in the bucket I had called untouchable. It is not — it existsonly because JSON cannot carry a u128 exactly, so a codec swap deletes it.
Re-measured with five buckets summing to the frame: at 10k rows native,
decode14.8ms and
quoting12.6ms of a 31.0ms frame; at 50k, quoting (77.5ms) costsmore than the JSON parser (76.6ms). Corrected ceiling: ~8.5× native, and
only 1.7× for a wasm frame — because there the rAF floor and socket receipt
are another 45% that no decoder touches. My published figure understated native by
~4.5×. Retracted and corrected on #9.
And the measurement found something better than either answer — #69
quote_big_intshas no guard, while its siblingquote_wide_intshas anecessary-condition guard and short-circuits. On a table with no 128-bit column
the hand-written path scans the whole frame and every row to rewrite nothing:
40–44% of the native frame, for one plain
find. The evidence was hiding in plainsight — going typed halves the quote bucket purely because the guarded function
replaces the unguarded one.
This is the cheapest real optimisation the milestone turned up, it takes much of
BSATN's ground with no protocol surface re-opened, and it should land before #67
since it halves what time-slicing has to spread.
Phase 5 status
stdb/auth.luapresent, no
dev/leakage, every module resolves withpackage.pathrestricted to the archive alone, and both README archive figures re-measure
correctly.
before they freeze, now open as #68:
auth.exchange'stokenoption →credential(it collided with five frozen uses oftoken, and theimplementation already renamed it internally); the
http_seamcallback dropserrforstatus == 0(itserrwas discarded by its only consumer whileinverting the SDK-wide
(err, ...)rule — a seam written in house styleturned a 401 into four requests); the auth cache nests under an
authkey(a flat provider map shared a namespace with
connect's record, andprovider = "token"returned the identity token); andspread_for→backoff_spread. #68 also makesconnect's save merge, whichcloses the third collision direction nesting alone could not.
Also filed this milestone
STDB_STATE_DIRleak a serverherd, and #19 does not cover it
quote_big_intsRecorded, not pursued: a malformed bearer token panics a tokio worker in 2.8.2
(
spacetimedb-jsonwebtoken-9.3.0/src/decoding.rs:199) and takes the server down.Worth stating about the process
Every single review round found something real, and the majority of the findings
corrected work I had done or claims I had made — including two published figures,
an inverted engine-API claim, and a measurement that missed 40% of the frame. Two
defects were only ever going to be caught by running the harness rather than the
unit tests: a circular
requirethatbobrefuses to build, and a storage seamthat made the documented configuration silently useless.
v1.1.0 is tagged and published
mainata606406, tagv1.1.0=46b433e, release published with the tagannotation as its body.
Verified against the live tag artifact, not a local
git archive: 13 entries(the 12 shipped files plus the forge's own path prefix, exactly as the README now
documents),
stdb/auth.luapresent,version = 1.1.0shipped, zerodev/leakage. Then a real consumer install — extract the zip, set
package.pathto italone,
requireall seven modules — resolves cleanly, and the new surfacebehaves:
auth.exchange,http_seam,backoff_spread, andbackoff_delay'sfourth parameter both spreading and no-opping on
nil.Phase 5
What shipped
server_pid()identifies our server from its argvstdb/auth.lua,auth.exchange, the SDK's first HTTP seamTwo behaviour changes worth repeating, both invisible to any released consumer
because the surfaces involved were added in this same release:
sys_storage'sloadno longer filters on.token(which had made the documented auth storageconfiguration silently useless), and
connect's identity save merges into itsslot instead of rewriting it.
Left open, deliberately
STDB_STATE_DIRcan leak a serveridentity, so a fleet relaunching into an outage is not covered. Arguably the
more important herd
quote_big_ints— the cheapest real optimisation found, and itshould land before #67 since it halves what time-slicing has to spread
ceiling is ~6–8× native, not the 1.8× I first published
recorded during this release gate that I could not attribute
account, and dropping
continue-on-erroris a judgement on accumulated CIhistory
On the process
Every review round found something real, and most findings corrected work I had
done or claims I had made. The ones that mattered most:
pipefaildefect that made a healthy server read as absent, in a script thatalready documented that exact trap
requirethatbobrefuses to build, invisible to every unit test —it reached review only because I told the implementer conformance was unnecessary
because the test double modelled a seam the SDK does not ship
published figure wrong by ~4.5× on #9
header pass
inverted while fixing an earlier error
Three lessons worth keeping, all learned by nearly missing something:
its per-file
oklines, sotail -1showed a false green on a suite that wasnot running.
stdb/requires conformance, not just unit tests. Theharness is the only thing that compiles the bundle.
silicon — which is how three frame-budget figures survived until the truth
gate re-ran them.
Closing this
v1.1.0 shipped: tag
v1.1.0=46b433e, release published, artifact and a realconsumer install both verified.
I had left this open because two boxes were unticked. Checking the precedent, that
was the wrong call: #24, the v1.0.0 checklist, was closed with every box ticked and
nothing dangling — including its own manual, maintainer-only step. A release
tracker is meant to die with the release.
The two remaining items are not release-gate work and do not need this issue to
stay alive, because each is already its own tracked issue:
defold/extension-websocket. Needs a GitHub account.continue-on-errorfrom the HTML5 CI step. I posted findingsthere:
conformance.ymlhas 8 runs (6 success, 2 failure), butcontinue-on-errormakes run-level green indistinguishable from "HTML5 failedand was swallowed", and the API serves no per-step results — so the evidence
only exists as job logs in the web UI. That issue now carries a proposal to make
future runs leave an API-visible signal, which would make the decision cheap
instead of manual-forever.
Follow-up work this milestone created, all tracked independently: #69
(
quote_big_intsunguarded, ~40% of the apply frame), #67 (time-slice theapplying frame), #65 (mass cold start still lockstepped), #63 (shared
state dir leaks a server). Recommended order is #69 before #67 — #69 roughly
halves what time-slicing has to spread, and it moves the thresholds #67 would be
tuned against.