Commit 9e3af10
Add regression test for subquery materializer multi-chunk log replay (bug 4) (#4670)
## Summary
Adds a deterministic regression test for **bug 4** from the
restore-from-file bug triage in #4648 (bug doc:
`packages/sync-service/bugs.md`).
This is a **test-only** change. Bug 4's production fix — the two
main-log short-circuits in
`Materializer.read_history_up_to_subscribed/2` — already shipped
alongside the bug 1 fix in #4651; it just lacked dedicated regression
coverage.
## Problem (bug 4)
On startup recovery the subquery materializer replays the source shape's
persisted history (snapshot + main log) up to its subscribed offset.
`Storage.get_log_stream/3` returns one chunk per call for the
**snapshot**, but returns the **entire** requested range for the **main
log** in a single call. When the source shape's main log spans more than
one chunk, a replay loop that keeps advancing through chunk boundaries
past the first main-log chunk re-reads main-log entries it has already
applied. Re-applying a `NewRecord` for an existing key raises `Key ...
already exists`, crashing the materializer (and taking the dependent
shape's consumer down with it → 409 must-refetch on the next poll).
## Solution / coverage
The fix (already merged in #4651) stops iterating as soon as the read
steps into the main log. This PR adds the missing regression test:
`test/electric/shapes/consumer/materializer_test.exs` →
`"does not re-read main-log entries when the main log spans multiple
chunks"`
- Sets `chunk_bytes_threshold: 10` to force the source shape's main log
across ≥2 chunks (asserts the first main-log chunk ends strictly before
the subscribed offset).
- Persists two `NewRecord` inserts in separate main-log chunks,
subscribes past both, and asserts startup replay yields the correct
`value_counts` exactly once.
## Test Plan
- [x] Passes with the fix in place (`59 tests, 0 failures` in the file).
- [x] Fails without the fix: reverting the short-circuits makes the test
crash with `** (RuntimeError) Key "public"."test_table"/"3" already
exists` from `read_history_up_to_subscribed/2` — confirming it's a
genuine failing-first regression test.
- [x] `mix format --check-formatted` clean.
## Notes
An end-to-end variant in `oracle_restore_test.exs` was prototyped but
not included: it does trigger the crash, but the failure self-heals via
a client refetch that re-syncs to the oracle, so it passes with and
without the fix — false-confidence coverage. The deterministic unit test
is the reliable regression guard.
---
Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>1 parent ec98959 commit 9e3af10
1 file changed
Lines changed: 87 additions & 0 deletions
Lines changed: 87 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1437 | 1437 | | |
1438 | 1438 | | |
1439 | 1439 | | |
| 1440 | + | |
| 1441 | + | |
| 1442 | + | |
| 1443 | + | |
| 1444 | + | |
| 1445 | + | |
| 1446 | + | |
| 1447 | + | |
| 1448 | + | |
| 1449 | + | |
| 1450 | + | |
| 1451 | + | |
| 1452 | + | |
| 1453 | + | |
| 1454 | + | |
| 1455 | + | |
| 1456 | + | |
| 1457 | + | |
| 1458 | + | |
| 1459 | + | |
| 1460 | + | |
| 1461 | + | |
| 1462 | + | |
| 1463 | + | |
| 1464 | + | |
| 1465 | + | |
| 1466 | + | |
| 1467 | + | |
| 1468 | + | |
| 1469 | + | |
| 1470 | + | |
| 1471 | + | |
| 1472 | + | |
| 1473 | + | |
| 1474 | + | |
| 1475 | + | |
| 1476 | + | |
| 1477 | + | |
| 1478 | + | |
| 1479 | + | |
| 1480 | + | |
| 1481 | + | |
| 1482 | + | |
| 1483 | + | |
| 1484 | + | |
| 1485 | + | |
| 1486 | + | |
| 1487 | + | |
| 1488 | + | |
| 1489 | + | |
| 1490 | + | |
| 1491 | + | |
| 1492 | + | |
| 1493 | + | |
| 1494 | + | |
| 1495 | + | |
| 1496 | + | |
| 1497 | + | |
| 1498 | + | |
| 1499 | + | |
| 1500 | + | |
| 1501 | + | |
| 1502 | + | |
| 1503 | + | |
| 1504 | + | |
| 1505 | + | |
| 1506 | + | |
| 1507 | + | |
| 1508 | + | |
| 1509 | + | |
| 1510 | + | |
| 1511 | + | |
| 1512 | + | |
| 1513 | + | |
| 1514 | + | |
| 1515 | + | |
| 1516 | + | |
| 1517 | + | |
| 1518 | + | |
| 1519 | + | |
| 1520 | + | |
| 1521 | + | |
| 1522 | + | |
| 1523 | + | |
| 1524 | + | |
| 1525 | + | |
| 1526 | + | |
1440 | 1527 | | |
1441 | 1528 | | |
1442 | 1529 | | |
| |||
0 commit comments