Repository navigation
Dev - #20
Merged
Merged
Dev#20
Conversation
…er flag events - SDK keys ship in browser and mobile bundles but were accepted as workspace admins everywhere. They now only reach the SDK routes (/stream, /flags/snapshot, reading flags, impressions/events) for their bound environment; admin/editor gates and handler fallbacks reject them. - Impression and event ingest authorize the caller: an SDK key for that environment, or a user with write access (no viewers, no read_only PATs). - Publish through a redis ConnectionManager so a broken connection is replaced. A publish that still fails is delivered to local SSE clients and a RESYNC broadcast is retried until Redis is back; SSE handlers close their streams on RESYNC, and the subscriber triggers one after resubscribing. - Flags carry a revision from a global sequence, bumped by trigger on every update. UPSERT/DELETE events and the SSE bootstrap include it so clients can drop events that arrive out of commit order. - The default-environment index is per project, and switching the default clears the old one first (it returned 500). - Integration and SSE e2e suites use an admin PAT for management calls and cover the new SDK-key scope, ingest authorization, default switching, revisions, and publisher/subscriber recovery.
…nalytics Node, Web and Flutter (React Native follows with its native-module commit): - A (re)connect no longer clears the live flag set. The replay is staged and swapped in on "ready", so isReady() never sits over an empty store and a replay cut short by a dropped stream is discarded. On reconnect, listeners fire for flags that actually changed. - Change events carrying a revision are ignored when older than the one already applied (and a deleted flag only returns with a newer revision). Events from older servers without revisions still apply. - Impressions carry evaluated_at and conversions occurred_at from the moment they happen, so independently flushed batches keep their real order for experiment attribution.
UpdateFlag encodes Flag with omitempty, so an emptied rule list, variants, prerequisites, tags, or a removed description were left out of the PATCH and kept their stored values. ReplaceFlag sends every clearable field explicitly ([] / null). Terraform and the Kubernetes operator now use it. UpdateFlag stays a partial update and documents that it cannot clear fields. Docs no longer offer SDK keys for these tools; they need a read_write PAT.
The server pages GET /environments/{env}/flags (200 by default), and both
clients made a single request, silently hiding flags beyond the first page
from dashboard search/comparison and from generated CLI types. Both now page
at the server maximum (500) until a short page.
…angelog - SDK keys only reach the SDK endpoints for their environment; automation (Terraform, the operator, scripts, CI) uses personal access tokens. - Ingest authorization and the evaluated_at/occurred_at fields. - SSE events carry a revision; clients stage reconnect replays until "ready", and the server closes streams to force a resync after missed updates.
… bindings The package never compiled or linked its Rust library, and nothing native called installCheckgateJSI(), so connect() could not work on a device. - Android: a Java module + package (autolinked) whose synchronous install() hands the JS runtime to a JNI adapter; Gradle runs cargo ndk for the app's ABIs before CMake, which links the static library with ReactAndroid::jsi (prefab enabled, abiFilters matched to the Rust ABIs). - iOS: an ObjC++ module with the same install(), and a CocoaPods build phase that compiles the engine for the active SDK/architectures and links it. - JS calls NativeModules.Checkgate.install() when the JSI global is missing. - bundle-rust.js resolves workspace-inherited manifest fields and makes the packed crate its own workspace root, so it builds from node_modules. - Same staged-bootstrap, revision and timestamp changes as the other SDKs. - CI packs the package, builds it outside the repo, and links an Android libcheckgate.so for every ABI with no undefined symbols. Verified: an RN 0.76.9 app consuming the packed tarball assembles with libcheckgate.so in the APK. Not yet run on a device or built for iOS.
- Rust: rustls 0.23.46 (RUSTSEC-2026-0346/0347), quinn-proto 0.11.19 (RUSTSEC-2026-0338..0342), xxhash-rust 0.8.19, and the yanked chacha20 and spin releases. `cargo deny check` and `cargo audit` are clean. - Web/RN SDKs: vitest 4.1.12 (with @vitest/mocker), postcss 8.5.30 and source-map-js 1.2.2 via vite. - RN SDK: stop auto-installing the react/react-native peer dependencies for local development (.npmrc legacy-peer-deps). Tests stub react-native, and the peer tree was the only source of the shell-quote, image-size, browserslist and baseline-browser-mapping alerts. - Node SDK: js-yaml 4.3.2. - Docs: postcss 8.5.30 and source-map-js 1.2.2. - Terraform provider: grpc 1.83.1.
…gs per project - Segment PATCH used COALESCE for the description, so it could never be cleared. `"description": null` now clears it; an omitted field still keeps the stored value. - The Go client gains ReplaceSegment (null description, [] rules when empty); the Terraform segment resource uses it, so a description or rules removed from configuration are cleared on the server. - Environment slugs were UNIQUE across all projects (a constraint older than projects), so a second project could not create its own "production". The constraint is now a (project_id, slug) unique index.
…in bootstrap - A segment create/update/delete changes the expanded payload of every flag that uses it, but republished them under the old revision, so SDKs (which accept equal revisions) could not tell an old expansion from the new one. The referencing flags now get a new revision inside the segment's transaction, and their events are rendered from that same snapshot. - A client that bootstrapped after a delete had no revision for the deleted key, so a delayed event from before the delete brought the flag back. A trigger records each deleted flag's last revision in flag_tombstones (kept for a day), and the bootstrap replays them as DELETE events. - The bootstrap reads segments, flags, and tombstones in one REPEATABLE READ transaction, so each revision matches the content it is sent with.
…lied _applySnapshot() fired onChange while it was still applying flags, so a listener evaluating a flag could see some of its prerequisites updated and others not. All four SDKs now apply every upsert, deletion, and revision (and persist the cache) before notifying. Tests also cover a bootstrap tombstone rejecting a delayed older event.
…ment A segment change re-expands the flags that reference it from inside its transaction, but flag writes and segment writes both took only a FOR SHARE lock on the environment, so they never waited for each other. A flag created (or re-pointed at the segment) while a segment change was in flight missed its scan, expanded against the old, still-visible segment after committing, and never received a corrective event. Segment writes now lock the environment row FOR NO KEY UPDATE, which excludes the FOR SHARE every flag write takes: either the flag write commits first and the segment's scan includes it, or it waits and expands against the committed segment. apply_patch_in_tx takes the share lock itself (before the flag row lock), so change-request approvals, which did not lock the environment, are covered too. The SSE e2e test holds an in-flight flag write open and checks that the segment edit waits and republishes that flag with the new rules.
Fix/review findings
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
Type of change
Testing
cargo test --workspacepassesChecklist