DATA?: journalrace probe saw 45 Log entries where 38 creates succeeded (under load 54, with request timeouts) #147

Closed
opened 2026-09-26 00:18:23 +00:00 by kayg · 7 comments
Owner

From job/search-correct's full adversarial run 2 (load ~54): 'journalrace: entry count :: expected 38, got 45' together with several journalrace request timeouts. Did not repeat on a targeted rerun at load 39. Most likely the probe counts only 201 responses, so creates that timed out client-side but completed server-side show up as 'extra' — harmless. But it could also be a double-append (e.g. the store::update retry redoing an edit that already landed, #98), which would be data corruption. Settle it: (1) make the probe tag every create with a unique marker and assert each marker appears at most once and every 201 marker appears exactly once (timeouts may or may not appear, never twice); (2) review store::update's retry: can a write that succeeded be reported as a conflict and redone? (replace_if semantics, fsync/rename ordering, error mapping); add a deterministic test that injects a failure after the rename but before the success return and asserts no duplicate line; (3) run the journalrace section 20x under synthetic load and report.

From job/search-correct's full adversarial run 2 (load ~54): 'journalrace: entry count :: expected 38, got 45' together with several journalrace request timeouts. Did not repeat on a targeted rerun at load 39. Most likely the probe counts only 201 responses, so creates that timed out client-side but completed server-side show up as 'extra' — harmless. But it could also be a double-append (e.g. the store::update retry redoing an edit that already landed, #98), which would be data corruption. Settle it: (1) make the probe tag every create with a unique marker and assert each marker appears at most once and every 201 marker appears exactly once (timeouts may or may not appear, never twice); (2) review store::update's retry: can a write that succeeded be reported as a conflict and redone? (replace_if semantics, fsync/rename ordering, error mapping); add a deterministic test that injects a failure after the rename but before the success return and asserts no duplicate line; (3) run the journalrace section 20x under synthetic load and report.
Author
Owner

Starting on branch job/journal-dup from base 1bd9cfeb3d. I will verify the retry guard with the deterministic post-rename failure tests, tighten and repeat the journalrace probe under synthetic load, then review other retrying writers.

Starting on branch job/journal-dup from base 1bd9cfeb3dd1b4a9d79dbf1ad5b330c56c365aa. I will verify the retry guard with the deterministic post-rename failure tests, tighten and repeat the journalrace probe under synthetic load, then review other retrying writers.
Author
Owner

Probe review finding: already treats timed-out concurrent creates as unknown outcomes and checks their unique markers, but its six seed creates still call , so a client timeout is reported as non-SLOW before the same marker rule runs. I am applying the timeout rule to seeds too; non-timeout statuses remain checked, and markers still must occur at most once.

Probe review finding: already treats timed-out concurrent creates as unknown outcomes and checks their unique markers, but its six seed creates still call , so a client timeout is reported as non-SLOW before the same marker rule runs. I am applying the timeout rule to seeds too; non-timeout statuses remain checked, and markers still must occur at most once.
Author
Owner

Probe review finding: the journalrace probe already treats timed-out concurrent creates as unknown outcomes and checks their unique markers, but its six seed creates still call check(..., expect=201). A client timeout is therefore reported as non-SLOW NO RESPONSE before the same marker rule runs. I am applying the timeout rule to seeds too. Non-timeout statuses remain checked, and markers still must occur at most once.

Probe review finding: the `journalrace` probe already treats timed-out concurrent creates as unknown outcomes and checks their unique markers, but its six seed creates still call `check(..., expect=201)`. A client timeout is therefore reported as non-SLOW `NO RESPONSE` before the same marker rule runs. I am applying the timeout rule to seeds too. Non-timeout statuses remain checked, and markers still must occur at most once.
Author
Owner

The broad local-server adversarial pass reached journalrace: 6 seed creates and 40 concurrent creates all returned 201; the probe found 46 entries, with no duplicate, lost or phantom create marker. Three move requests exceeded the 30 s client timeout and were reported as SLOW; they did not create a data-integrity finding. I found and am fixing the seed-timeout classification gap before the 20-run soak.

The broad local-server adversarial pass reached `journalrace`: 6 seed creates and 40 concurrent creates all returned 201; the probe found 46 entries, with no duplicate, lost or phantom create marker. Three move requests exceeded the 30 s client timeout and were reported as `SLOW`; they did not create a data-integrity finding. I found and am fixing the seed-timeout classification gap before the 20-run soak.
Author
Owner

The 20th synthetic-load pass exercised the timeout case: 14 create requests timed out, 3 of those markers later appeared, and the marker audit found 35 entries (6 seeds + 26 returned 201 + 3 timed-out creates that landed), with no duplicate/lost/phantom marker. The probe also reported 7 move: ('gone', id) hard findings because entries() converts every non-200 response, including a timed-out GET, to an empty list. This is a probe classification defect, not evidence that the Log entry is gone. I am fixing the lookup result and will repeat the soak.

The 20th synthetic-load pass exercised the timeout case: 14 create requests timed out, 3 of those markers later appeared, and the marker audit found 35 entries (6 seeds + 26 returned 201 + 3 timed-out creates that landed), with no duplicate/lost/phantom marker. The probe also reported 7 `move: ('gone', id)` hard findings because `entries()` converts every non-200 response, including a timed-out GET, to an empty list. This is a probe classification defect, not evidence that the Log entry is gone. I am fixing the lookup result and will repeat the soak.
Author
Owner

The corrected soak passed runs 1–3. Run 4 exposed one more probe classification gap under host load: seven sync upload/download HTTP calls timed out, but the probe reported their raw ('create'/'download', -1, ...) tuples as hard findings. Two sync lines were accepted, and the Daily note still had the exact expected 45 entries (6 seeds + 38 creates answered 201 + 1 timed-out create that landed). I am classifying sync client timeouts as SLOW and checking each timed-out sync line at most once.

The corrected soak passed runs 1–3. Run 4 exposed one more probe classification gap under host load: seven sync upload/download HTTP calls timed out, but the probe reported their raw `('create'/'download', -1, ...)` tuples as hard findings. Two sync lines were accepted, and the Daily note still had the exact expected 45 entries (6 seeds + 38 creates answered 201 + 1 timed-out create that landed). I am classifying sync client timeouts as `SLOW` and checking each timed-out sync line at most once.
Author
Owner

Merged into dev and deployed to calternal.kayg.org at 6440a5f (gates: fmt, svelte-check 0 errors, 398 web tests, clippy, workspace tests all pass).

Merged into dev and deployed to calternal.kayg.org at 6440a5f (gates: fmt, svelte-check 0 errors, 398 web tests, clippy, workspace tests all pass).
kayg closed this issue 2026-09-26 10:25:40 +00:00
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/calternal#147
No description provided.