From 53699d6e884741876f39d11a8c3d134d42e0511d Mon Sep 17 00:00:00 2001 From: samanqrfk Date: Sat, 25 Jul 2026 02:48:24 -0700 Subject: [PATCH 1/2] Add a changelog, and stop the release tooling from stranding tags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three release-process gaps, all found after cutting v0.1.2. The README's FetchContent snippet still pinned v0.1.0, three releases stale, so the documented way to consume the library handed new users an old one. bump_version.cmake only ever rewrote version.h, so nothing kept that pin current. It now rewrites the pin too, and fails loudly if the pattern stops matching rather than silently skipping it. Git pushes no tags by default, and neither a plain `git push` nor a GUI client's Push button sends one. The release workflow triggers on the tag, so a tag left behind looks like a release that silently never happened — which is what kept happening, and it had to be fixed by hand each time. The script now sets push.followTags in the repo's local config, so any push carries annotated tags reachable from the commits it sends, and takes -DPUSH=ON to push the release commit and tag itself. Added CHANGELOG.md covering 0.1.0 through 0.1.2. The auto-generated release notes name a PR title, which does not tell someone upgrading that v0.1.2 changed how paginated_query behaves on an oversized or incomplete page. Verified by running the script end to end at a throwaway version: both files rewritten, commit and annotated tag created, push.followTags set. --- CHANGELOG.md | 51 ++++++++++++++++++++++++++++++++++++++ README.md | 2 +- scripts/bump_version.cmake | 46 +++++++++++++++++++++++++++++----- 3 files changed, 92 insertions(+), 7 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..c70ce85 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,51 @@ +# Changelog + +Notable changes per release. Versions follow [semantic versioning](https://semver.org/), +with the caveat that 0.x means the API may still move between minor versions. + +## [0.1.2] — 2026-07-25 + +### Changed + +- `convex::paginated_query` now splits an oversized page instead of resetting + pagination. A page's range is pinned by its query journal, so inserts into + that range make it grow; previously a page that outgrew the server's read + limits (`pageStatus: "SplitRequired"`) reset the whole session, dropping every + loaded page and snapping the list back to the first one. It is now split in + two at the server's `splitCursor`, with both halves bounded by explicit + `cursor`/`endCursor` and swapped in only once both have loaded, so loaded + pages stay put. Pages are also split on `SplitRecommended`, or once a page + grows past twice `initial_num_items`. This matches convex-js's + `usePaginatedQuery`. +- A page the server reports as `SplitRequired` may be missing part of its range, + so `paginated_snapshot::results` now stops before it and the status returns to + `loading_more` (or `loading_first_page`) until a split repairs it. Previously + such a page was published, which could leave a gap in the middle of the list. + Also matches `usePaginatedQuery`. +- An incomplete page the server gives no `splitCursor` for is left alone rather + than reset. Its subscription stays live, so a later result that fits the read + limits repairs it. A query too heavy to ever return a complete page leaves the + list loading, with no error — as in convex-js, which has no recovery path for + that case either. + +No public API change: `paginated_query`, `paginated_snapshot`, and +`pagination_status` are unchanged. + +## [0.1.1] — 2026-07-14 + +### Added + +- FetchContent consumption snippet in the README. + +## [0.1.0] — 2026-07-14 + +First release. Realtime sync client over the Convex WebSocket protocol (live +query subscriptions, ordered mutations with read-your-writes, actions, auth, +reconnection with jittered backoff), the `convex::paginated_query` helper, +`convex::http_client` for one-shot calls, file storage upload/download, and full +Convex value fidelity including Int64, Bytes, and non-finite floats. The +protocol core is sans-IO; a bundled IXWebSocket transport is optional. + +[0.1.2]: https://github.com/Potionify/convex-cpp/compare/v0.1.1...v0.1.2 +[0.1.1]: https://github.com/Potionify/convex-cpp/compare/v0.1.0...v0.1.1 +[0.1.0]: https://github.com/Potionify/convex-cpp/releases/tag/v0.1.0 diff --git a/README.md b/README.md index e5354b8..b735b8d 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ include(FetchContent) FetchContent_Declare( convex GIT_REPOSITORY https://github.com/Potionify/convex-cpp.git - GIT_TAG v0.1.0 + GIT_TAG v0.1.2 ) set(CONVEX_WITH_IXWEBSOCKET ON) # bundled desktop transport; omit if you supply your own FetchContent_MakeAvailable(convex) diff --git a/scripts/bump_version.cmake b/scripts/bump_version.cmake index e890792..dad6766 100644 --- a/scripts/bump_version.cmake +++ b/scripts/bump_version.cmake @@ -1,5 +1,6 @@ -# Bumps the library version (include/convex/version.h), commits, and creates -# the matching annotated tag. Run from anywhere inside the repo: +# Bumps the library version (include/convex/version.h and the README's +# FetchContent pin), commits, and creates the matching annotated tag. Run from +# anywhere inside the repo: # # cmake -DBUMP=patch -P scripts/bump_version.cmake # 0.1.0 -> 0.1.1 # cmake -DBUMP=minor -P scripts/bump_version.cmake # 0.1.0 -> 0.2.0 @@ -10,9 +11,18 @@ # Or use the wrappers (no quoting needed): scripts/bump_version.bat patch # on Windows, scripts/bump_version.sh patch on Linux/macOS. # -# Then publish (this triggers the release workflow): +# Publishing. The release workflow triggers on the tag, and git does not push +# tags by default — neither does a plain `git push` nor the Push button in a +# GUI client. A tag left behind that way looks like a release that silently +# never happened. So this script sets push.followTags in the repo's local +# config, which makes every subsequent push carry annotated tags reachable +# from the commits it sends. Publish with either: # -# git push origin main --tags +# cmake -DBUMP=patch -DPUSH=ON -P scripts/bump_version.cmake # bump + push +# git push origin main # after a bump +# +# Both send the tag. `git push origin main --tags` still works and is what to +# use if an earlier tag was stranded locally. if(NOT DEFINED BUMP) message(FATAL_ERROR "Pass -DBUMP=major|minor|patch|x.y.z (the -D must come before -P)") @@ -62,7 +72,24 @@ foreach(part MAJOR MINOR PATCH) endforeach() file(WRITE "${version_h}" "${content}") -execute_process(COMMAND git -C "${repo_root}" add include/convex/version.h +# The README's FetchContent snippet pins a tag. Left to a human it goes stale +# silently, and a stale pin hands every new user an old library. +set(readme "${repo_root}/README.md") +file(READ "${readme}" readme_content) +if(NOT readme_content MATCHES "GIT_TAG v[0-9]+\\.[0-9]+\\.[0-9]+") + message(FATAL_ERROR "No 'GIT_TAG vX.Y.Z' pin found in ${readme}; update it by hand " + "or fix this script's pattern") +endif() +string(REGEX REPLACE "GIT_TAG v[0-9]+\\.[0-9]+\\.[0-9]+" "GIT_TAG v${new_version}" + readme_content "${readme_content}") +file(WRITE "${readme}" "${readme_content}") + +# Make an ordinary push carry the tag. Without this the release workflow waits +# on a tag that never arrives, and the failure is silent. +execute_process(COMMAND git -C "${repo_root}" config --local push.followTags true + COMMAND_ERROR_IS_FATAL ANY) + +execute_process(COMMAND git -C "${repo_root}" add include/convex/version.h README.md COMMAND_ERROR_IS_FATAL ANY) execute_process(COMMAND git -C "${repo_root}" commit -m "Release v${new_version}" COMMAND_ERROR_IS_FATAL ANY) @@ -70,4 +97,11 @@ execute_process(COMMAND git -C "${repo_root}" tag -a "v${new_version}" -m "v${ne COMMAND_ERROR_IS_FATAL ANY) message(STATUS "${old_version} -> ${new_version}, committed and tagged v${new_version}") -message(STATUS "Publish with: git push origin main --tags") + +if(PUSH) + execute_process(COMMAND git -C "${repo_root}" push origin HEAD "v${new_version}" + COMMAND_ERROR_IS_FATAL ANY) + message(STATUS "Pushed the release commit and tag v${new_version}") +else() + message(STATUS "Publish with: git push origin main (push.followTags carries the tag)") +endif() From 05417687d60d654e94c07e2852fb536f94670e31 Mon Sep 17 00:00:00 2001 From: samanqrfk Date: Sat, 25 Jul 2026 02:50:01 -0700 Subject: [PATCH 2/2] Reference the upstream fix by commit, not by a number that is not a PR The convex-js split-cursor fix was recorded as #54981, which is their internal changeset id, not a GitHub issue. Written as get-convex/convex-js#54981 it renders as a cross-repo reference to something that does not exist. Point at commit 7ceee3e instead. --- src/paginated.cpp | 2 +- tests/paginated_test.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/paginated.cpp b/src/paginated.cpp index 661a528..b23d676 100644 --- a/src/paginated.cpp +++ b/src/paginated.cpp @@ -234,7 +234,7 @@ struct paginated_impl : std::enable_shared_from_this { s.first.key = ++next_key; // The first half starts where the original page started — NOT at the // beginning of the query. convex-js sent a null cursor here, which - // duplicated every item before the page (get-convex/convex-js#54981). + // duplicated every item before the page (convex-js commit 7ceee3e). s.first.cursor = orig->cursor; s.first.end_cursor = split_cursor; s.second.key = ++next_key; diff --git a/tests/paginated_test.cpp b/tests/paginated_test.cpp index d1a751d..5a5b788 100644 --- a/tests/paginated_test.cpp +++ b/tests/paginated_test.cpp @@ -472,7 +472,7 @@ TEST(Paginated, IncompletePageHidesItselfButNotThePagesBeforeIt) { } TEST(Paginated, SplitFirstHalfStartsAtTheOriginalPagesCursor) { - // Regression guard for get-convex/convex-js#54981: convex-js sent a null + // Regression guard for convex-js commit 7ceee3e: convex-js sent a null // cursor for the first half, so splitting any page but the first re-read // the list from the beginning and duplicated everything before it. harness h;