verification #
Jetstream client checks live beside the SDK so every run builds the checkout
under review. The official Go client remains pinned in checks/go.mod and
go.sum at 58c4d7f7a9130e53b40348ad3d1f7aafed0e4843. Update that reference
deliberately and review changed behavior; agreement alone is not correctness.
The harness originated in atproto-bench 28d83d1. Historical measurements
remain there.
run #
Requires Zig 0.16.0, Go 1.27.0, Bash, jq, Git, and GNU coreutils (including nproc). Dependency setup needs network access; all fixtures then use bounded local HTTP/WebSocket connections. No API key, production archive, or firehose is used.
checks/run ci # unit tests, examples, conformance, short measurements, regressions
checks/run release # same checks with the full repeated measurement matrices
Both commands check formatting and Go static analysis, run SDK tests in Debug and ReleaseSafe, build examples, and build the Zig adapter against the root build's SDK module. There is no separate SDK archive pin. The two client processes receive fresh instances of the same fixture and explicit expected outputs. The live dictionary fixture is copied unchanged from the original harness (Stream dictionary 20260811).
Results are written to checks/results/{ci,release}/ and printed into the
Tangled workflow log. Metadata identifies the commit, dirty state, toolchains,
reference client, platform, CPU count, optimization mode, and start time.
Keep metadata with raw measurements. Generated output is ignored by Git.
The script runs the regression lane last so a known semantic failure doesn't
hide the performance evidence. Any failed check makes the command fail.
For focused reruns after building:
zig-out/bin/conformance # 15 established conformance scenarios
zig-out/bin/conformance regressions # audited defects and controls
zig-out/bin/conformance load ci
zig-out/bin/conformance catchup ci
zig-out/bin/conformance catchup 100000 # one archive size, four repeats
correctness #
The established lane covers plain/compressed subscriptions, exact/wildcard filters, cursor deduplication, reconnect cursor preservation, dictionary refresh/fallback, callback refusal, real JSS pagination, and archive/live boundary overlap. Transcripts and request counts must match explicit expected outcomes for both clients. Error categories remain language-specific.
The regression lane adds terminal error callbacks, 120 unique DID filters, and archive kind admission before decoding, including malformed selected and excluded row controls. These intentionally assert the desired contract, not the current defective output. At introduction, SDK v0.1.5 fails the terminal continue, large-filter, and excluded-malformed-row cases. No expected-failure allowlist converts those results into success. These are release blockers until separately reviewed SDK fixes land.
Multi-host failover remains an SDK extension exercised by its own loopback unit tests. The single-host Go client cannot establish its correctness. Stream server retention, hot/cold cursor translation, and storage behavior need server fixtures; this client harness does not claim to cover them.
performance #
Correct delivery, request counts, checksums, and bounded completion gate every measurement. CPU/RSS/latency numbers are recorded, without arbitrary thresholds on shared CI hardware. Compare repeated distributions on comparable hardware before calling a difference a regression or an improvement.
| workload | every change | full release profile |
|---|---|---|
| live | 1k events at 1k/s; 10k at 10k/s; 100 at 1k/s with a 2ms handler | 4k at 1k/s; 20k at 10k/s; 1k with the slow handler |
| archive catch-up | 10k archived records | 10k, 100k, 1M archived records |
| repetitions | two, alternating Go/Zig order | four, alternating Go/Zig order |
Live runs use plain and dictionary compression. They verify every sequence, then report process CPU, peak RSS, lag p50/p99/max, payload bytes, and fixture scheduling lateness. Frames are prepared before consumer startup, except the first frame establishing the schedule. Lag includes fixture scheduling and socket queues. The slow handler tests a finite backlog, not an indefinitely bounded queue. Samples and sorting contribute to consumer CPU and memory.
Catch-up uses the official Go JSS writer, 1,000 records per block, and both zero and 20ms injected block-request delay. It verifies ordered delivery, a canonical-record checksum, one fetch per block, one live connection, and suppression of the overlapping archive boundary. Both clients set concurrency to four, but their fetch/decode policies differ; observed request concurrency is reported. Time runs from subscription initialization to the first new live event. Whole-process CPU includes startup, checksum work, and shutdown.
Both corpora are synthetic and compressible. Payload bytes exclude protocol framing. Server and clients share CPUs, although client CPU/RSS exclude the fixture process. Linux memory uses post-exec VmHWM sampling; macOS wait4 peak RSS can include inherited memory and is unsuitable for cross-client memory claims. CI is a reproducibility check, not production capacity certification.
Tangled and releases #
checks.yml runs on every branch push, pull requests targeting main, version
tags, and manual triggers. release.yml runs on release/** branch pushes
or manually before tagging and uses the full profile. Tool downloads are
versioned and SHA256-checked. The SDK
repository must select spindle.zzstoatzz.io; workflow files alone do not
enable CI. See Tangled's workflow documentation.
Prepare and commit all version/changelog changes first, then push that commit
on a release/<version> branch. Both required workflows start automatically.
For example, after preparing version 0.1.6:
git push origin HEAD:refs/heads/release/v0.1.6
Manual reruns use tg pipeline trigger HEAD --workflow release.yml. Inspect
verdicts with tg pipeline status and logs with tg pipeline logs. The CLI's
appview can lag the owner PDS; the release-branch push and readiness check do
not depend on that cache. Never interpret a missing CLI result as success.
Then run:
checks/release-ready
This refuses a dirty checkout, absent/missing CI, pending/failed/cancelled workflows, and successes from another commit. It consults the selected spindle's authoritative API and requires the newest run of each required workflow for HEAD to succeed. Only then create and push the version tag on that unchanged commit. Re-run after any amendment or merge commit. Tag-triggered CI is a follow-up check; it cannot replace verification before publication. This is an enforced check in the release procedure, not a server-side ban on manual Git tags.
Transport changes additionally require the bounded live smoke described in the repository release skill. Keep network failures separate from local fixture failures and resolve them before publishing.