Skip to content

fix(cold-store-reaper): D1 sync batches sized by bound-parameter budget - #933

Merged
dezren39 merged 2 commits into
mainfrom
cold-store-reaper-sync-fix
Oct 26, 2026
Merged

dezren39 merged 2 commits into
mainfrom
cold-store-reaper-sync-fix

Conversation

@dezren39

@dezren39 dezren39 commented Oct 26, 2026 •

Copy link
Copy Markdown
Member

Bug

cold-store sync-manifest failed live with D1 sync failed (HTTP 400) on table objects once the objects table reached 14 rows. Root cause: statements batched a flat D1_SYNC_BATCH_ROWS = 50 rows regardless of table shape. A statement costs rows × columns bound parameters, and D1 allows at most 100 bound parameters per query — objects has 8 columns, so 14 rows already made 112 params (50 rows would be 400).

Fix

  • Per-table batch size from column count: batch_rows = max(1, 90 // ncols) (D1_SYNC_PARAM_BUDGET = 90, headroom under the hard limit D1_MAX_PARAMS_PER_QUERY = 100). Resulting batches: objects 11 rows (88 params), bundles 9 (90), members 22 (88), transfer_ledger 15 (90), meta 45 (90). Applied in build_sync_statements for all five synced tables; the flat constant is gone.
  • Diagnosable failures: the HTTP-error path now includes the D1 API's own error text (errors[0].message from the response body, via a defensive d1_error_message helper with a raw-body fallback), so a failure reads e.g. D1 sync failed (HTTP 400) on table objects: <D1's message> — statements already sent are idempotent upserts, re-run to resume.

Tests

  • New regression test test_sync_many_objects_stays_under_d1_param_limit: seeds 30 extra objects (31 total) against the stubbed FakeD1 HTTP layer, asserts every statement carries ≤ 100 params, per-table arrived row counts equal the local manifest exactly, and objects splits into 3 statements at the 11-row batch.
  • test_sync_http_error_is_clear now also asserts the API's error text (fake failure) appears in the raised message.
  • Ablation-verified: both tests fail against the pre-fix cold_store.py — the regression test with AssertionError: 248 not less than or equal to 100, exactly the production failure mode.
  • Full suite: 17 tests, OK (1 skipped — the node worker-decoder proof, node_modules unavailable in this environment, same as before).

Stdlib only; no live Cloudflare/Google calls in tests.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

Muse Sweep added 2 commits October 26, 2026 01:21
…face D1 error text

D1 allows at most 100 bound parameters per query, but sync-manifest
batched a flat 50 rows per statement: objects has 8 columns, so the
statement carried 112 params at just 14 rows and D1 rejected it
(HTTP 400). Batch size is now computed per table from its column
count: batch_rows = max(1, 90 // ncols), so rows x columns stays
within a 90-parameter budget under the hard limit for every table.

Also include the D1 API's own errors[0].message in the HTTP-failure
message, so a failed sync is diagnosable from the CLI output alone.
Seed 30 extra objects (31 total) so the old flat 50-row batch would
emit one 248-parameter statement; assert every statement stays at or
under D1's 100 bound parameters, that per-table arrived row counts
match the local manifest exactly, and that objects splits into
3 statements at the 90 // 8 = 11-row batch. Verified failing on the
pre-fix code with '248 not less than or equal to 100'.

Also assert the HTTP-error message now carries the D1 API's own
error text ('fake failure' from the stub), not just the status.
@dezren39
dezren39 requested a review from a team as a code owner October 26, 2026 01:24
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-26T01:25:54.649492Z 36dd14b PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@coderabbitai

coderabbitai Bot commented Oct 26, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 27 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: d8ef25aa-b6c4-4a23-b873-5d84c3dda67d
Commits

Reviewing files that changed from the base of the PR and between 402b5aa and 36dd14b.

Files selected for processing: 2
  • pkgs/cold-store-reaper/cold_store.py
  • pkgs/cold-store-reaper/tests/test_cold_store.py
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant