feat: component-polish batch — network backpressure/rate-limit, client convergence/offline-parity, react useSyncExternalStore - #79
Merged
ivkan merged 2 commits intoJun 21, 2026
Conversation
…t convergence/offline-parity, react useSyncExternalStore Network (DEPTH_NETWORK_TRANSPORT F4/F5): - TODO-509: slow-consumer broadcasts no longer drop silently. ConnectionHandle gains try_send_broadcast: a full outbound channel drops the event (bounded memory) and advances a per-connection consecutive-drop counter; past slow_consumer_drop_threshold (default 256) the client connection is cancelled to force reconnect + Merkle resync instead of diverging silently. Adds a cumulative dropped_broadcasts metric; counter resets on any successful send; cluster peers exempt (failure-detector owns their liveness). CRDT/query/ pubsub live-push paths routed through it. - TODO-510: per-connection inbound op-rate TokenBucket on the WS data plane (default 20k ops/s sustained, 40k burst). One peer's OpBatch flood is throttled with a 429 back-off without tearing the connection down; op-cost counts batch ops so packing cannot evade the cap. Client (DEPTH_CLIENT_SDK F8/F11): - TODO-500: LWWMap.adoptServerEcho reconciles the server's arrival-order re-stamp of our own optimistic write (value-equality guarded → no data loss) so memory/disk/Merkle converge with the server. SyncEngine.applyServerEvent now gates the storage put on merge/adopt instead of persisting the rejected echo unconditionally (the memory/disk HLC skew bug). - TODO-501: offline runLocalQuery now applies sort+limit (shared comparator with the hybrid path) and explicitly rejects cursor/groupBy/aggregations rather than silently dropping them; live pre-load degrades gracefully on reject. React (DEPTH_REACT F1/F2/F5/F6, folds TODO-516): - TODO-515: migrate the 12 subscription hooks to useSyncExternalStore (with a <18 shim) for synchronous cached snapshots (no first-render loading flash), tearing-freedom, and no isMounted anti-pattern. useMap/useORMap drive re-renders via a stable version-counter snapshot while still returning the live map; handle lookups memoized by name (render-purity, F5). QueryHandle/ HybridQueryHandle/SearchHandle/HybridSearchHandle gain cached, referentially- stable getSnapshot accessors. useTopic no longer re-subscribes on inline callback identity change (TODO-516 folded). Tests: connection slow-consumer (7, incl. draining/reset/cluster-peer negative controls) + TokenBucket (7) + inbound_op_cost; LWWMap adoptServerEcho + SyncEngine put-gating (incl. divergence + no-data-loss controls); QueryManager offline sort/limit + unsupported-clause rejection; react useSyncExternalStore migration (8) + useTopic subscribe-count/StrictMode.
Deploying topgun with
|
| Latest commit: |
c918a71
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://f3c94abb.topgun-f45.pages.dev |
| Branch Preview URL: | https://feat-cleanup-batch-network-c.topgun-f45.pages.dev |
- websocket: 429 rate-limit reply is best-effort try_send, not await — a flooding client is behind on its outbound channel, so awaiting would stall the read loop on the very connection being throttled. - LWWMap.valuesEqual: depth guard (>64) so a pathological/cyclic in-memory value can't stack-overflow the server-echo reconcile path. - LWWMap.adoptServerEcho: precondition rejecting a strictly-newer server record (plain merge already wins it) — never downgrade through the echo path. - connection: document relaxed-ordering safe-failure on the broadcast drop path.
ivkan
deleted the
feat/cleanup-batch-network-client-react-todo509-510-500-501-515
branch
June 21, 2026 16:11
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Component-polish cleanup batch ahead of core freeze — three independent groups, each fixing a G9 depth-audit finding with a behavioral test + a negative control (the bug reproduces before the fix).
Group 1 — Network / transport (
DEPTH_NETWORK_TRANSPORTF4/F5)ConnectionHandle::try_send_broadcastreplaces the silenttry_senddrop on the live-push paths (CRDT delta, query update, pub/sub). A full outbound channel still drops the event (memory stays bounded) but advances a per-connection consecutive-drop counter; once it reachesslow_consumer_drop_threshold(default 256) the client connection is cancelled to force reconnect + Merkle resync instead of diverging silently. Adds a cumulativedropped_broadcastsmetric; the counter resets on any successful send; cluster peers are exempt (the failure detector owns their liveness).TokenBucketin the WS Phase-2 read loop caps inbound op rate per connection (default 20 000 ops/s sustained, 40 000 burst). A single peer'sOpBatchflood is throttled with a best-effort 429 back-off without tearing the connection down ("отбой, не падение"); op-cost is charged per op so packing many ops into one batch cannot evade it.Group 2 — Client SDK (
DEPTH_CLIENT_SDKF8/F11)LWWMap.adoptServerEcho()reconciles the server's arrival-order re-stamp of our own optimistic write: when LWW rejects the echo because our clock briefly led the server, it adopts the server's authoritative timestamp only when the value is unchanged (value-equality guarded → no data loss) so memory, disk, and the Merkle tree converge with the server.SyncEngine.applyServerEventnow gates the storageputon merge/adopt instead of the unconditionalputthat created the memory/disk HLC skew.runLocalQuerynow appliessort+limitoffline (sharing one comparator with the hybrid path) and explicitly rejectscursor/groupBy/aggregationsrather than silently dropping them; the live-query pre-load degrades gracefully on reject.Group 3 — React bindings (
DEPTH_REACTF1/F2/F5/F6; folds TODO-516)useSyncExternalStoremigration. All 12 subscription hooks move touseSyncExternalStore(with a<18shim) for synchronous cached snapshots (no first-render loading flash), tearing-freedom under concurrent rendering, and removal of theisMountedanti-pattern.useMap/useORMapdrive re-renders via a stable version-counter snapshot while still returning the live mutable map; handle lookups are memoized by name (render purity, F5).QueryHandle/HybridQueryHandle/SearchHandle/HybridSearchHandlegain cached, referentially-stablegetSnapshot()accessors.useTopicno longer re-subscribes on inline-callback identity change (TODO-516 folded in).Cross-vendor adversarial review (GLM-5.2)
Ran on the correctness-critical diffs (509/510 + 500). Acted on the real findings: the rate-limit 429 is now best-effort
try_send(no read-loop stall on a slow client); added a recursion-depth guard to the value comparator and a timestamp-precondition guard toadoptServerEcho; documented the relaxed-ordering disconnect as a safe (resync, no-data-loss) failure mode. Bounded/non-issues (Batch undercount, async-put ordering, sort insertion order) evaluated and dismissed with rationale.Test plan / gates (all green locally)
@topgunbuild/core: 2074 passed (+ newadoptServerEchoconvergence/no-data-loss/tombstone/depth tests)@topgunbuild/client: 660 passed (+SyncEngineput-gating,QueryManageroffline sort/limit/reject)@topgunbuild/react: 203 passed (+useSyncExternalStoremigration suite,useTopicsubscribe-count/StrictMode)topgun-serverlib: 1425 passed (+ slow-consumer 7,TokenBucket7,inbound_op_cost)cargo clippy --all-targets --all-features -- -D warnings: clean ·cargo fmt --check: cleanpnpm test:sim: 4 passed ·pnpm format:check: clean ·pnpm lint: 0 errorspnpm test:integration-rust(blocking gate): see CI🤖 Generated with Claude Code