Establishes version control for the personal Logseq DB fork before starting the server-client architecture migration and domain features described in docs/agent-guide and the approved implementation plan. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
86 KiB
86 KiB
Sync Stress Failed Cases
Recording rule for CLI sync stress failures
- Date added: 2026-07-01
- Scope:
scripts/cli-concurrent-edit-stress.mjs, localdb-syncserver runs, and multi-client CLI sync stress graphs. - Rule: every hard failure or suspicious no-op from the stress harness must get an entry in this file before the issue is considered handled.
- Required fields for each entry: graph, command or log path, symptom, root cause, fix, regression test or stress verification, and current status.
- Do not mark a case fixed from a retry alone. A fixed case needs a concrete root cause and a post-fix run or targeted test that covers the same path.
CLI tag-name resolution failed during expanded stress
- Date: 2026-07-01
- Graph:
cli-test-5 - Command:
node scripts/cli-concurrent-edit-stress.mjs --graph cli-test-5 --concurrency 3 --sync --offline --offline-ms 800 --timeout-ms 20000 --max-ops 80 --extra-pages 2 --journal-pages 2 --journal-start 2026-07-01 - Symptom:
upsert block --update-tags '["cli-stress-tag-a"]'failed withCannot parse :find, expected: (find-rel | find-coll | find-tuple | find-scalar). - Root cause: OCaml CLI tag-name resolution used a duplicated Datascript class query path for tag names. Numeric tag ids worked, but string tag names failed before the outliner mutation was applied.
- Regression test:
cli/test/test_cases.mlnow coversupsert block --update-tags '["Tag A"]'resolving throughthread-api/cli-list-tags. - Fix: tag-name resolution in
cli/lib/upsert.ml,cli/lib/add.ml, andcli/lib/update.mlnow uses the existing tag list endpoint instead of the broken query path. - Sync status after the failed stress smoke: local and remote tx both reached
71, pending queues were zero, and checksums matched (b18d36f60f52de7e).
CLI sync stress failed cases from multi-client expansion
Fresh 5000-op stress verification after sync fixes
- Date: 2026-07-01
- Graphs:
cli-sync-stress-assert-20260701-1cli-sync-stress-5000-20260701-13cli-sync-stress-5000-20260701-15cli-sync-stress-5000-20260701-snapshot-last-error-1
- Commands:
- Assertion run:
DB_SYNC_CHECKSUM_ASSERT=true LOGSEQ_BIN=/Users/tiensonqin/Codes/projects/logseq/static/logseq-cli.js node scripts/cli-concurrent-edit-stress.mjs --graph cli-sync-stress-assert-20260701-1 --config tmp/cli-sync-stress-assert-20260701-1/cli.edn --root-dir tmp/cli-sync-stress-assert-20260701-1/root --log-file tmp/cli-sync-stress-assert-20260701-1/events.jsonl --clients 3 --concurrency 8 --max-ops 5000 --sync --offline --no-e2ee --timeout-ms 20000 --settle-attempts 60 --settle-ms 1000 - Normal run:
LOGSEQ_BIN=/Users/tiensonqin/Codes/projects/logseq/static/logseq-cli.js node scripts/cli-concurrent-edit-stress.mjs --graph cli-sync-stress-5000-20260701-13 --config tmp/cli-sync-stress-multi-5000-20260701-13/cli.edn --root-dir tmp/cli-sync-stress-multi-5000-20260701-13/root --log-file tmp/cli-sync-stress-multi-5000-20260701-13/events.jsonl --clients 3 --concurrency 8 --max-ops 5000 --sync --offline --no-e2ee --timeout-ms 20000 --settle-attempts 60 --settle-ms 1000 - Reject rollback run:
LOGSEQ_BIN=/Users/tiensonqin/Codes/projects/logseq/static/logseq-cli.js node scripts/cli-concurrent-edit-stress.mjs --graph cli-sync-stress-5000-20260701-15 --config tmp/cli-sync-stress-multi-5000-20260701-15/cli.edn --root-dir tmp/cli-sync-stress-multi-5000-20260701-15/root --log-file tmp/cli-sync-stress-multi-5000-20260701-15/events.jsonl --clients 3 --concurrency 8 --max-ops 5000 --sync --offline --no-e2ee --timeout-ms 20000 --settle-attempts 60 --settle-ms 1000 - Snapshot-last-error run:
LOGSEQ_BIN=/Users/tiensonqin/Codes/projects/logseq/static/logseq-cli.js node scripts/cli-concurrent-edit-stress.mjs --graph cli-sync-stress-5000-20260701-snapshot-last-error-1 --config tmp/cli-sync-stress-snapshot-last-error-5000-1/cli.edn --root-dir tmp/cli-sync-stress-snapshot-last-error-5000-1/root --log-file tmp/cli-sync-stress-snapshot-last-error-5000-1/events.jsonl --clients 3 --concurrency 8 --max-ops 5000 --sync --offline --no-e2ee --timeout-ms 20000 --settle-attempts 60 --settle-ms 1000
- Assertion run:
- Result:
cli-sync-stress-assert-20260701-1completed5001started ops, all clients settled at tx6074, final recomputed/local/remote checksum was75663df27432e5c6, and finalgraph validatepassed on all three clients.cli-sync-stress-5000-20260701-13completed5001started ops, final recomputed/local/remote checksum wasf3b46db99d7293d1on all three clients, and finalgraph validatepassed on all three clients.cli-sync-stress-5000-20260701-15completed5001started ops after the rejected-local-tx rollback fix, final recomputed/local/remote checksum was7c746bd7fb4ba9b3on all three clients, and finalgraph validatepassed on all three clients.cli-sync-stress-5000-20260701-snapshot-last-error-1completed5001started ops after the snapshot-last-error fix and bundle rebuild, final recomputed/local/remote checksum was5790fdbc975a6b36on all three clients, and finalgraph validatepassed on all three clients.cli-sync-stress-5000-20260701-20completed5001started ops after the property-batch stale target fix and bundle rebuild, final recomputed/local/remote checksum wasfc3492f6c370efe4on all three clients, and finalgraph validatepassed on all three clients.- The snapshot-last-error run's event log had no
sync-start-runtime-error,pending-tx-snapshot-changed,apply-remote-txs-failed, fatal event, error-level event, checksum mismatch marker, orprev-checksum-not-matchentry. - The db-sync server log for the normal run had no
:before-checksum-error,server checksum doesn't match,prev-checksum-not-match,last-error, or exception entries.
- Non-fatal anomalies:
cli-sync-stress-5000-20260701-15had one recovered:db-sync/apply-remote-txs-failedworker log on client 3. The run later converged and validated; the transient failure is tracked in the open recovered remote-apply case below.cli-sync-stress-5000-20260701-18completed5001started ops, final recomputed/local/remote checksum3cce9543989a7855on all three clients, and finalgraph validatepassed on all three clients. It still logged a recovered severe:db-sync/apply-remote-txs-failedafter exhausting the immediate snapshot-drift retry budget; that is tracked in the delayed snapshot retry case below and this run is not counted as final verification for that later fix.cli-sync-stress-5000-20260701-20had three localhttp-set-block-propertyoperations classified asrace-conflictbecause their target blocks were deleted concurrently. Those HTTP handler exceptions are documented below and are not remote apply, checksum, or validation failures.
- Status: five fresh 5000-op runs passed after rebuilding
static/db-worker-node.js; the latest run also verified the property-batch stale target fix at event/final-state and worker-log remote-apply level.
Fresh 10000-op stress verification after sync fixes
- Date: 2026-07-01
- Graph:
cli-sync-stress-10000-20260701-1 - Command:
LOGSEQ_BIN=/Users/tiensonqin/Codes/projects/logseq/static/logseq-cli.js node scripts/cli-concurrent-edit-stress.mjs --graph cli-sync-stress-10000-20260701-1 --config tmp/cli-sync-stress-multi-10000-20260701-1/cli.edn --root-dir tmp/cli-sync-stress-multi-10000-20260701-1/root --log-file tmp/cli-sync-stress-multi-10000-20260701-1/events.jsonl --clients 3 --concurrency 8 --max-ops 10000 --sync --offline --no-e2ee --timeout-ms 20000 --settle-attempts 90 --settle-ms 1000 - Result:
- Completed
10001started ops with 3 clients, offline windows, offline today-journal races, HTTP outliner ops, undo/redo, recycle/delete, and multi-client offline rebase operations. - Final
thread-api/recompute-checksum-diagnosticsreturned recomputed/local/remote checksum6a1402088d63be44for all three clients. - Final
graph validatepassed on all three clients. - Post-run
sync statuson all three clients reportedlast-error nil,ws-state "open",local-tx 12134,remote-tx 12134, all pending queues0, and local/remote checksum6a1402088d63be44. - The db-sync server log had no
:before-checksum-error,server checksum doesn't match,prev-checksum-not-match,last-error, or exception entries.
- Completed
- Non-fatal anomalies:
http-delete-restore-pagestill returned HTTP 200 withresultTransit falsefour times. This is tracked in the open page-delete no-op case below.- One
tag-delete-recreatedelete phase returnedtag-not-found. The run still converged and validated. Root cause: the stress harness uses a shared volatile tag name, so another worker can delete the tag before the current worker's delete phase runs. Fix: classifytag-not-foundduringtag-delete-recreatedelete as an expected race, matching the existing volatile property delete classification. Regression test:scripts/cli-concurrent-edit-stress.test.mjscovers this classifier path.
- Status: passed. This did not reproduce reverse-local-tx, apply-remote-tx, or checksum divergence failures.
Final 1000-op smoke verification after classifier update
- Date: 2026-07-01
- Graph:
cli-sync-stress-1000-20260701-final - Command:
LOGSEQ_BIN=/Users/tiensonqin/Codes/projects/logseq/static/logseq-cli.js node scripts/cli-concurrent-edit-stress.mjs --graph cli-sync-stress-1000-20260701-final --config tmp/cli-sync-stress-multi-1000-20260701-final/cli.edn --root-dir tmp/cli-sync-stress-multi-1000-20260701-final/root --log-file tmp/cli-sync-stress-multi-1000-20260701-final/events.jsonl --clients 3 --concurrency 8 --max-ops 1000 --sync --offline --no-e2ee --timeout-ms 20000 --settle-attempts 60 --settle-ms 1000 - Result:
- Completed
1001started ops with 3 clients and offline simulation. - Final recomputed/local/remote checksum was
628f67429199e958on all three clients. - Final
graph validatepassed on all three clients. - Post-run
sync statuson client 1 reportedlast-error nil,ws-state "open",local-tx 1087,remote-tx 1087, all pending queues0, and local/remote checksum628f67429199e958.
- Completed
- Status: passed after the volatile tag delete race classifier update.
Targeted test verification after final stress updates
- Date: 2026-07-01
- Commands and results:
rtk node --test scripts/cli-concurrent-edit-stress.test.mjs scripts/cli-sync-stress-workflow.test.mjs: 30 tests, 0 failures.rtk bb dev:test -v frontend.worker.db-sync-test/validated-transact-retries-when-live-conn-changes-before-commit-test -v frontend.worker.db-sync-test/prepare-upload-tx-entries-drops-empty-txs-test -v frontend.worker.db-sync-test/apply-remote-txs-reverses-parent-insert-with-existing-child-without-orphaning-test -v frontend.worker.db-sync-test/sync-counts-refreshes-idle-stale-local-checksum-test -v frontend.worker.db-sync-test/apply-remote-txs-rechecks-local-txs-when-local-delete-races-temp-snapshot-test -v frontend.worker.db-sync-test/apply-remote-txs-rechecks-local-txs-when-local-delete-races-temp-commit-test -v frontend.worker.db-sync-test/apply-remote-txs-delays-retry-when-local-txs-keep-changing-test -v frontend.worker.db-sync-test/apply-remote-txs-retries-snapshot-drift-even-if-pending-list-stabilizes-test -v frontend.worker.db-sync-test/apply-remote-txs-local-delete-parent-remote-move-then-delete-parent-test -v frontend.worker.db-sync-test/apply-remote-txs-overlap-out-of-order-parent-delete-then-move-repairs-test: 10 tests, 48 assertions, 0 failures.rtk bb dev:test -v frontend.worker.db-sync-test/temp-conn-batch-preserves-cardinality-one-schema-test -v frontend.worker.db-sync-test/rebase-local-insert-then-save-keeps-cardinality-one-values-test -v frontend.worker.db-sync-test/apply-remote-txs-skips-stale-move-before-later-delete-test -v frontend.worker.db-sync-test/apply-remote-txs-skips-stale-move-to-target-before-later-target-delete-test -v frontend.worker.db-sync-test/apply-remote-txs-with-local-changes-rejects-invalid-final-rebase-test -v frontend.worker.db-sync-test/receive-queue-failure-updates-last-sync-error-test -v frontend.worker.db-sync-test/sync-counts-refreshes-idle-stale-local-checksum-test: 7 tests, 21 assertions, 0 failures.rtk bb dev:test -v frontend.worker.db-sync-test/apply-remote-txs-repairs-missing-block-lookup-ref-test -v frontend.worker.db-sync-test/apply-remote-txs-repairs-missing-block-retract-lookup-ref-test -v frontend.worker.db-sync-test/apply-remote-txs-with-local-changes-repairs-missing-block-lookup-ref-test -v frontend.worker.db-sync-test/apply-remote-txs-with-local-changes-repairs-missing-block-datoms-test: 4 tests, 16 assertions, 0 failures.rtk pnpm --dir deps/db test-v logseq.db-test/batch-transact-with-temp-conn-preserves-cardinality-one-schema-test logseq.db-test/batch-transact-with-temp-conn-preserves-retracts-test: completed the deps/db suite, 114 tests, 418 assertions, 0 failures.rtk pnpm --dir deps/db test-v logseq.db-test/batch-transact-with-temp-conn-before-commit-can-abort-live-commit-test logseq.db-test/batch-transact-with-temp-conn-preserves-cardinality-one-schema-test logseq.db-test/batch-transact-with-temp-conn-preserves-retracts-test logseq.db-test/transact-sync-retries-when-live-conn-changes-before-commit-test: the targeted assertions printed as passing, but the full deps/db runner later stopped producing output ingc-kvs-table-testand was interrupted, so this invocation is not counted as a completed pass.rtk bb dev:test -v frontend.worker.pipeline-test/recycle-ops-return-apply-result-test: 1 test, 4 assertions, 0 failures.rtk pnpm --dir cli test: full CLI parity suite passed.
- Status: completed commands passed; the latest deps/db retry was interrupted after target assertions printed as passing and is not counted as a completed pass.
Latest PR 12842 verification
- Date: 2026-07-01
- Commands and results:
rtk pnpm cljs:run-test -n frontend.worker.db-sync-test -e fix-me: 206 tests, 750 assertions, 0 failures.rtk clojure -M:clj-kondo --parallel --lint src/main/frontend/worker/sync/apply_txs.cljs src/test/frontend/worker/db_sync_test.cljs: 0 errors, 0 warnings.rtk node --test scripts/cli-concurrent-edit-stress.test.mjs scripts/cli-sync-stress-workflow.test.mjs: 32 tests, 0 failures.rtk bb dev:lint-and-test: 1090 tests, 4730 assertions, 0 failures, with lint and translation checks passing.
- CLI stress verification:
cli-sync-stress-10000-20260701-6completed10001started ops with 3 clients, offline windows, offline today-journal races, HTTP outliner ops, undo/redo, recycle/delete, and multi-client offline rebase operations. Final recomputed/local/remote checksum was43da786afaaf37a8on all three clients, and finalgraph validatepassed on all three clients.cli-sync-stress-1000-20260701-230737completed1001started ops with 3 clients and offline simulation. Final recomputed/local/remote checksum wasdc4de34b2c9d2d8don all three clients, finalgraph validatepassed on all three clients, and the event log had no harderror,fatal,failed, orno-opentries. Expected stale-id races were classified asrace-conflict.
- Status: passed.
Duplicate local and remote create-page rebase could remove remote children
- Date: 2026-07-01
- Graph: reproduced by worker tests while investigating multi-client offline today-page creation.
- Symptom: when one client had a pending local
create-pageand remote txs contained the same page plus new child blocks, rebasing the localcreate-pagecould treat the page as absent or create a duplicate path instead of preserving the remote page entity and its children. - Root cause:
rebase-local-op!only looked up an existing page by the local page UUID from the outliner op options. If the same title had already arrived from remote, the rebase path could miss it and runoutliner-page/create!again instead of turning the local create into an idempotent page resolution. - Fix:
:create-pagerebase now resolves an existing active page by UUID first and then by title. If it finds one, it returns the existing page title and UUID instead of creating another page. - Regression tests:
frontend.worker.db-sync-test/rebase-create-page-keeps-page-uuid-testfrontend.worker.db-sync-test/rebase-duplicate-create-page-keeps-remote-children-testfrontend.worker.db-sync-test/apply-remote-txs-rebases-create-delete-page-as-recycled-test
- Status: fixed and covered by the latest 1000-op and 10000-op multi-client offline stress runs.
Remote recreate in the same batch was misclassified as a missing block repair
- Date: 2026-07-01
- Graph: reproduced by worker test from a local-delete and remote-recreate race.
- Symptom: if remote txs deleted a block and recreated the same
:block/uuidin the same batch while the client had a local delete pending, the apply path could ask server repair for that UUID as if it were missing before applying the remote recreate tx. - Root cause: missing-block preflight looked for absent lookup refs in the current DB and after local reversal, but it did not exclude block UUIDs that the incoming remote batch itself creates. Vector tx data was handled, but Datascript Datom tx data from remote apply was not part of the temp-id to UUID extraction path.
- Fix: remote apply now extracts created block UUIDs from both vector tx items and Datascript Datoms, subtracts UUIDs that are also retracted in the same batch, and excludes those remote-created UUIDs from missing-block repair preflight.
- Regression test:
frontend.worker.db-sync-test/apply-remote-tx-local-delete-remote-recreate-does-not-leave-local-only-delete-test. - Status: fixed and covered by latest stress verification.
Delayed snapshot retry returned an inconsistently awaitable result
- Date: 2026-07-01
- Graph: reproduced by
frontend.worker.db-sync-testfull namespace run after adding snapshot-drift retry tests. - Symptom: full namespace execution could see a delayed remote-apply retry continue after fixture cleanup, producing
missing-dbfromapply-remote-txs!. Focused tests were easier to pass because the async cleanup race was narrower. - Root cause: the snapshot-drift retry path returned nested or mixed native/Promesa promise values. The delayed retry branch could be observed as complete before the recursive retry finished, so callers and tests could clean up the repo connection while retry work was still scheduled.
- Fix: retry construction now uses one explicit Promesa chain via
<retry-apply-remote-txs!andp/thenfor delayed retry. The tests' Datascript fixture cleanup also treats any thenable throughjs/Promise.resolve(...).finally(...)so native and Promesa promise values share one lifecycle. - Regression tests:
frontend.worker.db-sync-test/apply-remote-txs-rechecks-local-txs-when-local-delete-races-temp-snapshot-testfrontend.worker.db-sync-test/apply-remote-txs-rechecks-local-txs-when-local-delete-races-temp-commit-testfrontend.worker.db-sync-test/apply-remote-txs-delays-retry-when-local-txs-keep-changing-testfrontend.worker.db-sync-test/apply-remote-txs-retries-snapshot-drift-even-if-pending-list-stabilizes-test
- Status: fixed;
frontend.worker.db-sync-testfull namespace passes.
Volatile property delete became ambiguous during 10000-op retry
- Date: 2026-07-01
- Graph:
cli-sync-stress-10000-20260701-2 - Command:
LOGSEQ_BIN=/Users/tiensonqin/Codes/projects/logseq/static/logseq-cli.js node scripts/cli-concurrent-edit-stress.mjs --graph cli-sync-stress-10000-20260701-2 --config tmp/cli-sync-stress-multi-10000-20260701-2/cli.edn --root-dir tmp/cli-sync-stress-multi-10000-20260701-2/root --log-file tmp/cli-sync-stress-multi-10000-20260701-2/events.jsonl --clients 3 --concurrency 8 --max-ops 10000 --sync --offline --no-e2ee --timeout-ms 20000 --settle-attempts 90 --settle-ms 1000 - Symptom: the retry was interrupted after
1588started ops becauseproperty-delete-recreatedelete returnedambiguous-property-nameforcli-stress-volatile-prop; the CLI reported two matching candidate property ids. - Root cause: the stress harness intentionally uses one shared volatile property name while multiple workers concurrently delete and recreate it. Under that race, more than one property entity with the same display name can exist, and
remove property --nameis correctly ambiguous. This is the same volatile-resource race class asproperty-not-found, not evidence of sync divergence by itself. - Fix: classify
ambiguous-property-nameduringproperty-delete-recreatedelete as an expected race conflict so the harness keeps stressing sync convergence instead of failing on an invalid name selector. - Regression test:
scripts/cli-concurrent-edit-stress.test.mjscovers bothproperty-not-foundandambiguous-property-namefor concurrent volatile property delete. - Status: fixed in the stress harness; the interrupted run is not counted as final stress verification.
Local sync server was not started for --sync
- Date: 2026-06-30
- Graph:
pi-memory - Command:
node scripts/cli-concurrent-edit-stress.mjs --graph pi-memory --concurrency 8 --sync --timeout-ms 20000 - Symptom: fatal preflight error:
Local db-sync server is not healthy at http://127.0.0.1:18080/health. - Root cause: the stress harness required a local
db-syncserver for--syncbut only checked health; it did not start the local server itself. - Fix: the harness now starts
cli-e2e/scripts/db_sync_server.pyautomatically for local--syncruns unless--no-start-sync-serveris passed, and it rejects non-local--sync-basevalues. - Regression test:
scripts/cli-concurrent-edit-stress.test.mjscovers local sync server start args. - Status: fixed in the stress harness.
Sync start tried to refresh auth against the wrong local endpoint
- Date: 2026-06-30
- Graph:
pi-memory - Command:
node scripts/cli-concurrent-edit-stress.mjs --graph pi-memory --concurrency 8 --sync --timeout-ms 20000 - Symptom:
sync startfailed withauth-refresh-failed,Run logseq login first, and a local HTTP 404 response. - Root cause: the graph was not initialized/uploaded to the local sync server before
sync start, so the CLI entered the normal auth-refresh path instead of the local stress upload path. - Fix:
ensureLocalServersnow checkssync status; when the graph is uninitialized it sets local graph E2EE metadata when requested, runssync ensure-keyswhen needed, uploads the graph to the local sync server, and only then starts sync. - Regression test:
scripts/cli-concurrent-edit-stress.test.mjscovers local sync upload/ensure-key argument construction. - Status: fixed in the stress harness.
Concurrent edit used stale block ids after another worker deleted the target
- Date: 2026-06-30
- Graph:
pi-memory - Example failure:
upsert block --graph pi-memory --id 1911 --target-id 1902 --pos last-child- Error:
source-not-found,source block uuid not found - Another example:
target-not-found,target block uuid not found
- Root cause: the stress harness intentionally lets workers delete, recycle, move, and update from a shared live-id pool. Under concurrency, an id can be selected and then deleted by another worker before the mutation runs. That is a valid race for the harness, not by itself a sync corruption signal.
- Fix: CLI
source-not-found,target-not-found,block-not-found,page-not-found,recycled-page, andupsert-id-not-foundare classified asrace-conflict; stale ids are dropped from the live pool and the pool is refreshed from the graph. - Regression test:
scripts/cli-concurrent-edit-stress.test.mjscovers stale id extraction and expected race classification. - Status: fixed as a harness classification issue. A final checksum mismatch or graph validation failure after these race conflicts would still be treated as a real sync failure.
Sync runtime kept last-error after duplicate :block/uuid
- Date: 2026-06-30
- Graph:
pi-memory - Command:
node scripts/cli-concurrent-edit-stress.mjs --graph pi-memory --concurrency 8 --sync --timeout-ms 20000 - Symptom:
sync startreached an open websocket but failed becausesync statushadlast-error:Cannot add #datascript/Datom [... :block/uuid #uuid "06ef6144-c02c-469c-8296-7fc8e2220782" ...] because of unique constraint. - Root cause: remote tx application with local changes used the live Datascript connection while reversing local txs, applying remote txs, and replaying local txs. An exception during that pipeline could leave the live connection in an intermediate state even though
batch-transact!resets the conn on a single failed batch. - Fix:
apply-remote-tx-with-local-changes!now usesbatch-transact-with-temp-conn!, so reverse/apply/replay happens against a temporary connection and only the final successful result is committed to the live connection. - Regression tests:
frontend.worker.db-sync-test/apply-remote-txs-with-local-changes-rejects-invalid-final-rebase-testfrontend.worker.db-sync-test/rebase-local-insert-then-save-keeps-cardinality-one-values-test
- Status: fixed in sync remote tx application.
Receive queue failures were invisible to sync status
- Date: 2026-07-01
- Graph: reproduced by worker test, originally found while investigating CLI stress failures.
- Symptom: a receive-loop exception could stop remote application while
sync statusdid not expose the failure throughlast-error, making a yellow/stuck sync indicator hard to diagnose. - Root cause:
enqueue-receive-message!logged the exception but did not update the client sync error state. - Fix: the receive queue catch path now calls
sync-util/set-last-sync-error!before logging. - Regression test:
frontend.worker.db-sync-test/receive-queue-failure-updates-last-sync-error-test. - Status: fixed in sync worker error reporting.
Release CLI failed to reuse a starting db-worker-node server
- Date: 2026-07-01
- Graphs:
cli-sync-stress-1000-20260701-1- earlier
5000stress attempt before the release CLI fix
- Symptom: stress run failed with
server-start-failed,failed to publish health, or transientfetch failedwhen many CLI commands started while db-worker-node was still starting or temporarily busy. - Root cause: the release CLI discovered servers only through successful
/healthzresponses, treated HTTP 503startinghealth payloads as absent, and did a one-shot final health lookup after spawning. Under concurrent CLI startup this could spawn duplicate workers or fail while the existing worker was almost ready. - Fix:
cli/lib/server_runtime.mlnow accepts 200 and 503 health payloads for discovery, waits up to 30 seconds for published/ready servers, respects a live db-worker lock before spawning another worker, and retries final health discovery until ready. - Regression tests:
CLI parity server start reuses starting db-worker-nodeCLI parity ensure server retries final health discovery
- Post-fix stress verification:
cli-sync-stress-1000-20260701-2completed with 3 clients,1001started ops, all final checksums equal to94e75da4b4bf1f78, and all three finalgraph validatechecks passing. - Status: fixed in release CLI server lifecycle handling.
Recycle restore/permanent-delete returned no observable apply result
- Date: 2026-07-01
- Graph: reproduced by outliner pipeline test while expanding HTTP
apply-outliner-opsstress coverage. - Symptom:
thread-api/apply-outliner-opscould return HTTP 200 with a nil/false result for recycle restore or permanent delete, so the stress harness could not distinguish a successful operation from a silent no-op. - Root cause:
logseq.outliner.op/apply-op!did not set*resultfor:restore-recycledand:recycle-delete-permanently. - Fix: both op branches now return their mutation result through
*result. - Regression test:
frontend.worker.pipeline-test/recycle-ops-return-apply-result-test. - Status: fixed in outliner op result reporting.
Remote move before later remote delete failed after local reversal removed the moved block
- Date: 2026-07-01
- Graph:
cli-sync-stress-5000-20260701-1 - Command:
LOGSEQ_BIN=static/logseq-cli.js node scripts/cli-concurrent-edit-stress.mjs --graph cli-sync-stress-5000-20260701-1 --clients 3 --concurrency 8 --max-ops 5000 --sync --offline --no-e2ee --timeout-ms 20000 --settle-attempts 60 --settle-ms 1000 - Log evidence:
tmp/cli-sync-stress-multi-5000-20260701-1/events.jsonl, line6052tmp/cli-sync-stress-multi-5000-20260701-1/clients/client-2/root/graphs/cli-sync-stress-5000-20260701-1/db-worker-node-20260701.log
- Symptom: client 2 got stuck with
last-error:Nothing found for entity id [:block/uuid #uuid "912166d7-e42f-400b-bb8d-b1b120d44a66"]. - Runtime evidence: client 2 had
ws-state "open",local-tx 1776,remote-tx 2425,pending-local 327,pending-server 649, and checksum mismatch; clients 1 and 3 had settled atlocal-tx 2425,remote-tx 2425, checksumc3635870ab8ca030. Client 2graph validatestill passed, so this was sync apply/rebase failure, not local DB validation corruption. - Root cause: while applying remote txs with local changes, repair preflight checked missing remote lookup refs against the live DB before reversing local pending txs. The block UUID existed at that point, so no repair was fetched. The isolated rebase then reversed local pending txs and removed the same block. The next remote tx
t=1779tried to move that now-missing block, and a later remote txt=1788deleted the same block. Datascript threw before the later delete could make the stale move irrelevant. The same class can happen when the moved block still exists but the move target is removed by local reversal and later deleted by the remote batch. - Fix: remote tx application now drops stale operation datoms when a block ref used by that operation is already missing in the current apply DB and the current or later remote tx batch contains
:db/retractEntityfor that same:block/uuid. This keeps delete-wins ordering without masking missing blocks that are not actually deleted by the remote batch. - Regression tests:
frontend.worker.db-sync-test/apply-remote-txs-skips-stale-move-before-later-delete-testfrontend.worker.db-sync-test/apply-remote-txs-skips-stale-move-to-target-before-later-target-delete-test- Adjacent repair/rebase tests still pass:
apply-remote-txs-repairs-missing-block-lookup-ref-test,apply-remote-txs-repairs-missing-block-retract-lookup-ref-test,apply-remote-txs-with-local-changes-repairs-missing-block-lookup-ref-test,apply-remote-txs-with-local-changes-repairs-missing-block-datoms-test,apply-remote-txs-with-local-changes-rejects-invalid-final-rebase-test,apply-remote-txs-local-delete-parent-remote-move-then-delete-parent-test,apply-remote-txs-overlap-out-of-order-parent-delete-then-move-repairs-test.
- Post-fix stress verification:
cli-sync-stress-5000-20260701-13andcli-sync-stress-10000-20260701-1both completed with 3 clients, offline windows, matching final checksums, and finalgraph validatepassing on all clients. - Status: fixed and verified in fresh 5000-op and 10000-op stress runs.
Open: all clients settled locally but final remote checksum differed
- Date: 2026-07-01
- Graph:
cli-sync-stress-5000-20260701-8 - Command:
LOGSEQ_BIN=/Users/tiensonqin/Codes/projects/logseq/static/logseq-cli.js node scripts/cli-concurrent-edit-stress.mjs --graph cli-sync-stress-5000-20260701-8 --config tmp/cli-sync-stress-multi-5000-20260701-8/cli.edn --root-dir tmp/cli-sync-stress-multi-5000-20260701-8/root --log-file tmp/cli-sync-stress-multi-5000-20260701-8/events.jsonl --clients 3 --concurrency 8 --max-ops 5000 --sync --offline --no-e2ee --timeout-ms 20000 --settle-attempts 60 --settle-ms 1000 - Symptom: after 5000 requested ops, final sync settle failed on client 1 with
local-tx 6130,remote-tx 6130, all pending queues at0,last-error nil,ws-state "open", local checksumd497a453c0029f4d, and remote checksum755f4eb4fee7ed74. - Current evidence:
- All three clients reported the same sync status values and the same local checksum, but all disagreed with the remote checksum.
- Final
graph validatepassed on all clients, but datom counts differed: client 1 had8762datoms, client 2 had8779, and client 3 had8770. - The event log includes one transient
fetch failedfollowed by server port refreshes, and an earlierhttp-delete-restore-pageHTTP 200 no-op withresultTransit false.
- Follow-up diagnostics:
- Client-side
thread-api/recompute-checksum-diagnosticsrecomputedd497a453c0029f4don all three clients, matching each client's local checksum and disagreeing with the remote checksum reported bysync status. - Direct server checksum diagnostics for graph id
e54e9868-e4c9-47b1-8f40-d3974e0cefc9recomputedd497a453c0029f4d, matching the clients. The server SQLitesync_meta.checksumrow still stored the stale value755f4eb4fee7ed74. - The server tx log had rows from
t=1throught=6130, andsync_meta.twas also6130, so the mismatch was isolated to stored checksum metadata rather than missing tx rows. find-checksum-driftcould not replay this server DB from an empty DB because the tx log depends on the initial uploaded graph snapshot and built-in entities. That tool needs a snapshot-aware replay path before it can locate checksum drift for upload-created graphs.
- Client-side
- Additional verification:
- Added an opt-in server assertion path guarded by
DB_SYNC_CHECKSUM_ASSERT=truethat recomputes the server checksum after each appended tx and throws withprev-tx,prev-checksum, recomputed checksum, tx meta, DB-before, and tx data when stored incremental metadata drifts. - Diagnostic run
cli-sync-stress-assert-20260701-1completed5001started ops with 3 clients, offline mode, final tx6074, final checksum75663df27432e5c6on all clients, and finalgraph validatepassing on all clients. - The diagnostic server log had no
:before-checksum-error,server checksum doesn't match, orprev-checksum-not-matchentries.
- Added an opt-in server assertion path guarded by
- Root cause: still pending for the original stale
sync_meta.checksumwrite. The direct server recompute shows the graph content itself matched clients in this run, but the stored checksum metadata had drifted. The assertion run did not reproduce the drift, so this case must stay open. - Fix: pending. The assertion path is diagnostic only and must not be counted as the root-cause fix.
- Regression test or stress verification: pending. Do not mark fixed from a retry alone; first identify why
sync_meta.checksumcould stay stale whilesync_meta.tand server graph contents reached the final tx. - Status: open.
Idle sync status exposed stale cached local checksum
- Date: 2026-07-01
- Graphs:
cli-sync-stress-5000-20260701-11cli-sync-stress-1000-20260701-snapshot-race-1
- Commands:
LOGSEQ_BIN=/Users/tiensonqin/Codes/projects/logseq/static/logseq-cli.js node scripts/cli-concurrent-edit-stress.mjs --graph cli-sync-stress-5000-20260701-11 --config tmp/cli-sync-stress-multi-5000-20260701-11/cli.edn --root-dir tmp/cli-sync-stress-multi-5000-20260701-11/root --log-file tmp/cli-sync-stress-multi-5000-20260701-11/events.jsonl --clients 3 --concurrency 8 --max-ops 5000 --sync --offline --no-e2ee --timeout-ms 20000 --settle-attempts 60 --settle-ms 1000LOGSEQ_BIN=/Users/tiensonqin/Codes/projects/logseq/static/logseq-cli.js node scripts/cli-concurrent-edit-stress.mjs --graph cli-sync-stress-1000-20260701-snapshot-race-1 --config tmp/cli-sync-stress-snapshot-race-1000-1/cli.edn --root-dir tmp/cli-sync-stress-snapshot-race-1000-1/root --log-file tmp/cli-sync-stress-snapshot-race-1000-1/events.jsonl --clients 3 --concurrency 8 --max-ops 1000 --sync --offline --no-e2ee --timeout-ms 20000 --settle-attempts 60 --settle-ms 1000
- Symptom: the 5000-op run completed
5001started ops, but final settle failed on client 2.sync statusreportedlast-error nil,ws-state "open",local-tx 6035,remote-tx 6035, all pending queues at0, local checksum759e50784194968c, and remote checksuma661d1ec5864f400. The later 1000-op regression run hit the same idle synced shape withlocal-tx 1098,remote-tx 1098, all pending queues at0, remote checksumd4ce1df5e969232b, butlocal-checksum nil. - Evidence:
- Client 1 and client 3 already matched the remote checksum
a661d1ec5864f400. - Client 2
graph validatepassed with no invalid entities. - Calling
thread-api/recompute-checksum-diagnosticson client 2 immediately returned recomputed/local/remote checksuma661d1ec5864f400, and the followingsync statusalso reported the matching checksum. - In
cli-sync-stress-1000-20260701-snapshot-race-1, client 1 recomputed and validated with checksumd4ce1df5e969232b; client 2 also passedgraph validate, but final settle checkedsync statusbefore recompute diagnostics and sawlocal-checksum nilfor all 60 attempts.
- Client 1 and client 3 already matched the remote checksum
- Root cause: sync status and RTC presence read the cached local checksum from client-ops metadata directly. Under these stress runs, that cache was stale or missing even though the Datascript graph itself could recompute to the remote checksum and there were no pending local/server queues. The first fix only refreshed when the cached local checksum was a string, so it handled stale string values but skipped a nil cache. Because no later tx arrived, the stale or nil cache stayed visible and final settle treated the graph as divergent.
- Fix:
frontend.worker.sync.presence/sync-countsnow detects the idle mismatch state (pending-local,pending-asset, andpending-serverare zero;local-tx == remote-tx; cached local checksum is nil or differs from remote checksum), recomputes the checksum from the live Datascript DB, updates the cached local checksum, and returns the recomputed value. A real DB divergence still remains visible because the recomputed checksum will continue to differ from the remote checksum. - Regression test:
frontend.worker.db-sync-test/sync-counts-refreshes-idle-stale-local-checksum-testcovers both stale string and nil cached local checksums. - Post-fix stress verification:
cli-sync-stress-5000-20260701-13,cli-sync-stress-10000-20260701-1,cli-sync-stress-1000-20260701-final, andcli-sync-stress-5000-20260701-snapshot-last-error-1all ended withlocal-tx == remote-tx, all pending queues at0, and matching local/remote/recomputed checksums. The latest fresh 5000-op run used the rebuilt worker bundle and did not reproduce stale or nil checksum status. - Status: fixed by targeted test and fresh stress verification.
Open: sync start timed out with RTC closed and pending local changes
- Date: 2026-07-01
- Graph:
cli-sync-stress-5000-20260701-12 - Command:
LOGSEQ_BIN=/Users/tiensonqin/Codes/projects/logseq/static/logseq-cli.js node scripts/cli-concurrent-edit-stress.mjs --graph cli-sync-stress-5000-20260701-12 --config tmp/cli-sync-stress-multi-5000-20260701-12/cli.edn --root-dir tmp/cli-sync-stress-multi-5000-20260701-12/root --log-file tmp/cli-sync-stress-multi-5000-20260701-12/events.jsonl --clients 3 --concurrency 8 --max-ops 5000 --sync --offline --no-e2ee --timeout-ms 20000 --settle-attempts 60 --settle-ms 1000 - Symptom: during
offline-today-journal-race, severalsync startcalls timed out before the websocket reachedopen. The status hadlast-error nil,ws-state "closed",pending-localgreater than0,pending-server 0,local-tx == remote-tx, and differing local/remote checksums. - Evidence:
- One failure reported
local-tx 3319,remote-tx 3319,pending-local 89,local-checksum "1a69e8c09ac59ca6", andremote-checksum "f6b91e5ab46a8394". - A manual status check while the run was still active reported
ws-state "closed",local-tx 3287,remote-tx 3287,pending-local 208,pending-server 0,local-checksum "2c50d29e2e5a8fde", andremote-checksum "f0bc605965fec2f1". - This matches the user-reported stuck-yellow shape: local changes are pending, the RTC state is closed, and a restart or refresh is needed before syncing resumes.
- The fresh rollback verification run
cli-sync-stress-5000-20260701-15reproduced the same transient shape. Examples: line15748hadws-state "closed",local-tx 5392,remote-tx 5392,pending-local 76, local checksum7525b61b47be8cd3, and remote checksumbcba6bfda0e2af3f; line15863hadws-state "closed",local-tx 5458,remote-tx 5458,pending-local 64, local checksum43bf131651448414, and remote checksumd2c8e8cc0ddf768a. - In
cli-sync-stress-5000-20260701-15, final settle eventually recovered without manual restart: all three clients ended with recomputed/local/remote checksum7c746bd7fb4ba9b3, and finalgraph validatepassed. This keeps the case open as a reconnect/retry issue, not a final convergence failure in that run.
- One failure reported
- Root cause: pending. The next diagnostic step is to determine whether
sync startis racing an explicit stop/offline transition, reusing a closed client without scheduling reconnect, or leaving inflight state uncleared. - Fix: pending.
- Regression test or stress verification: pending.
- Status: open.
Post-fix 5000-op run ended with zero-pending checksum mismatch on one client
- Date: 2026-07-01
- Graph:
cli-sync-stress-5000-20260701-14 - Command:
LOGSEQ_BIN=/Users/tiensonqin/Codes/projects/logseq/static/logseq-cli.js node scripts/cli-concurrent-edit-stress.mjs --graph cli-sync-stress-5000-20260701-14 --config tmp/cli-sync-stress-multi-5000-20260701-14/cli.edn --root-dir tmp/cli-sync-stress-multi-5000-20260701-14/root --log-file tmp/cli-sync-stress-multi-5000-20260701-14/events.jsonl --clients 3 --concurrency 8 --max-ops 5000 --sync --offline --no-e2ee --timeout-ms 20000 --settle-attempts 60 --settle-ms 1000 - Symptom: the run reached
5001started ops with no non-race errors during operation execution, then final settle failed on client 2. The final status hadlast-error nil,ws-state "open",local-tx 6138,remote-tx 6138, all pending queues at0, local checksum5a14c02ae03a8ea4, and remote checksumcaa4a33469ac5576. - Evidence:
- Final settle retried
sync status60 times for client 2 before failing. - The failure happened after rebuilding
static/db-worker-node.jswith the remote repair-after-local-reversal fix, so it is not the stale-code run fromcli-sync-stress-5000-20260701-12. - No
last-error,apply remote tx fail, or missing entity error appeared before final settle. thread-api/recompute-checksum-diagnosticsshowed a real local divergence, not a stale checksum cache: client 1 and client 3 recomputed tocaa4a33469ac5576with801checksum-visible blocks, while client 2 recomputed to5a14c02ae03a8ea4with797checksum-visible blocks.- Final
graph validatestill passed on client 2 (1040entities,808blocks,9609datoms), so the divergent DB shape is internally valid. - Comparing checksum block sets showed client 2 was missing exactly four blocks that client 1, client 3, and the server kept:
d959db93-2cb2-4054-980c-106f5b67e708:http insert stress-1782899803902 worker=4 seq=380 op=http-insert-blocks35b5799f-f2e9-49b8-be1b-7324cf676c18:http undo redo stress-1782899803902 worker=8 seq=328 op=http-insert-undo-redof13cc3da-b879-4e41-93c6-01a23ee0a5ee:child stress-1782899803902 worker=4 seq=442 op=create-child parent=38126a44e88b-c7dd-4e91-aa4d-0097fd768289:http batch stress-1782899803902 worker=6 seq=496 op=http-batch-set-property
- Server tx evidence for graph id
f1ba1b2c-995c-45a0-8fbf-d1ce1a23b786:t=3219createdd959db93-2cb2-4054-980c-106f5b67e708under parentfd0cd77a-4daf-4c45-981e-8153a6694fdf.t=3434inserted35b5799f-f2e9-49b8-be1b-7324cf676c18,t=3435deleted it, andt=3436reinserted the same UUID.t=3843moved the parent chain from the journal page to page6a44e51d-bf4e-4b30-96d2-4580dd316905.t=3937addedf13cc3da-b879-4e41-93c6-01a23ee0a5eeunder35b5799f-f2e9-49b8-be1b-7324cf676c18.t=4619added6a44e88b-c7dd-4e91-aa4d-0097fd768289.- Later txs recycled and restored page
6a44e51d-bf4e-4b30-96d2-4580dd316905, but no later server tx deleted these four blocks.
- Client 2
client_opshad one failed local tx:- tx id
1e43b525-dd7e-4bd8-9eca-67bce986db48,outliner_op=delete-blocks,pending=0,failed=1. - The normalized tx deleted
35b5799f-f2e9-49b8-be1b-7324cf676c18andd959db93-2cb2-4054-980c-106f5b67e708. - Its reverse tx contained the exact four missing blocks, including
f13cc3da-b879-4e41-93c6-01a23ee0a5eeand6a44e88b-c7dd-4e91-aa4d-0097fd768289.
- tx id
- Client 2 log line
1796showed the server rejected that tx withtx/reject,reason "db transact failed",t 4753, and the same failed tx id.
- Final settle retried
- Root cause: when the server rejected a local tx as non-recoverable, the client marked the tx
failed=1andpending=0but did not roll back the local Datascript mutation that had already been applied optimistically. The failed delete therefore remained in client 2's local graph while the server and other clients never accepted it. Because the tx was no longer pending, final sync status reachedlocal-tx == remote-tx, all pending queues at0, and nolast-error, but the local checksum stayed permanently different. - Fix:
tx/rejecthandling now rolls back rejected pending txs before marking them failed. The rollback reverses the rejected tx and any later pending local txs in a temporary connection, commits only a successful result to the live DB, and rebases later non-rejected pending txs so unrelated local edits remain queued. - Regression test:
frontend.worker.db-sync-test/tx-reject-db-transact-failed-rolls-back-rejected-local-delete-test. - Adjacent verification: the focused
tx/rejectsuite passed, includingtx-reject-db-transact-failed-surfaces-rejected-tx-test,tx-reject-db-transact-failed-marks-inflight-op-failed-test,tx-reject-db-transact-failed-rolls-back-rejected-local-delete-test,tx-reject-db-transact-failed-selectively-updates-inflight-ops-test,tx-reject-missing-blocks-keeps-failed-tx-pending-and-retries-with-repair-test, andtx-reject-stale-keeps-inflight-op-pending-test. - Post-fix stress verification: after rebuilding
static/db-worker-node.js,cli-sync-stress-5000-20260701-15completed5001started ops with final checksum7c746bd7fb4ba9b3on all three clients and finalgraph validatepassing on all three clients. Earlier fresh stress runscli-sync-stress-5000-20260701-13,cli-sync-stress-10000-20260701-1, andcli-sync-stress-1000-20260701-finalalso converged and validated. - Status: fixed and verified in fresh 5000-op, 10000-op, and 1000-op stress runs.
Remote apply failed on a missing block UUID after offline journal races
- Date: 2026-07-01
- Graph:
cli-sync-stress-5000-20260701-12 - Command:
LOGSEQ_BIN=/Users/tiensonqin/Codes/projects/logseq/static/logseq-cli.js node scripts/cli-concurrent-edit-stress.mjs --graph cli-sync-stress-5000-20260701-12 --config tmp/cli-sync-stress-multi-5000-20260701-12/cli.edn --root-dir tmp/cli-sync-stress-multi-5000-20260701-12/root --log-file tmp/cli-sync-stress-multi-5000-20260701-12/events.jsonl --clients 3 --concurrency 8 --max-ops 5000 --sync --offline --no-e2ee --timeout-ms 20000 --settle-attempts 60 --settle-ms 1000 - Symptom: after several offline start/stop windows and auto-created journal races, client 2 could reopen the websocket but stayed stuck with
last-error:Nothing found for entity id [:block/uuid #uuid "cb874a9d-e87a-4427-99d8-f6cacb931381"]. - Evidence:
- Event log line
10118showssync startreturningsync-start-runtime-errorwithws-state "open",local-tx 3545,remote-tx 3836,pending-local 265, andpending-server 291. - A later manual status check showed the same missing UUID with
local-tx 3545,remote-tx 3868,pending-local 279, andpending-server 323. - The primary client and client 3 continued past this point, so the failure is isolated to applying/rebasing remote txs on one client, not to server availability alone.
- Event log line
- Root cause: the failing client had local pending txs, so remote apply first reversed those local txs in an isolated rebase connection. The live DB still had enough data before reversal, so the existing pre-repair scan did not fetch the block. After local reversal, the block
cb874a9d-e87a-4427-99d8-f6cacb931381was gone, and remote txt=3700tried to move that same block with no later remote delete for it. The earlier stale move-before-delete fix correctly handled remote batches where the same missing block would be deleted later, but this case needed repair, not dropping. - Fix: remote apply now does an additional isolated dry-run of local reversal before fetching server repair data. Any remote block refs that become missing only after local reversal are fetched from the server and applied after reversal but before remote tx application. UUIDs that the same remote batch later retracts are excluded so the previous delete-wins stale behavior is preserved.
- Regression test:
frontend.worker.db-sync-test/apply-remote-txs-repairs-block-made-missing-by-local-reversal-test. - Adjacent verification: the repair/rebase suite passed, including
apply-remote-txs-repairs-missing-block-lookup-ref-test,apply-remote-txs-repairs-missing-block-retract-lookup-ref-test,apply-remote-txs-with-local-changes-repairs-missing-block-lookup-ref-test,apply-remote-txs-with-local-changes-repairs-missing-block-datoms-test,apply-remote-txs-skips-stale-move-before-later-delete-test,apply-remote-txs-skips-stale-move-to-target-before-later-target-delete-test, andapply-remote-txs-with-local-changes-rejects-invalid-final-rebase-test. - Post-fix stress verification:
cli-sync-stress-5000-20260701-13,cli-sync-stress-10000-20260701-1, andcli-sync-stress-1000-20260701-finalall completed withoutapply remote tx fail, missing block UUID runtime errors, or final checksum divergence. - Status: fixed and verified in fresh stress runs.
Reversing queued parent insert orphaned existing children during sync rebase
- Date: 2026-07-01
- Source: user report from
2.0.1-alpha+nightly.20260629; reproduced by targeted DB worker test on current branch before the fix. - Symptom: after a stale websocket gap and reconnect, sync replay/rebase reversed an earlier
insert-blockstransaction that deleted a parent block while children still referenced it. DB validation rejected the write withDB write failed with invalid data; the validation error included:block/parentmissing required key, and sync could freeze with queued server txs still pending. - Reproduction:
frontend.worker.db-sync-test/apply-remote-txs-reverses-parent-insert-with-existing-child-without-orphaning-testseeds a local graph with a queued inserted parent and an existing child under it, then leaves only the parent insert reverse in the pending queue. Before the fix, remote apply failed withDB write failed with invalid data; the tx data retracted the parent entity while the child still referenced the old parent entity id. - Root cause: raw reverse tx-data for
:insert-blockscan be narrower than the current local subtree. During remote apply with local changes,reverse-local-txs!applies reverse tx-data with validation skipped because intermediate rebase states may be temporarily invalid. If aninsert-blocksreverse contains[:db/retractEntity parent]but the current DB has children under that parent which are not also reversed, the final batch can leave those children pointing at a retracted parent. Rebase may then create a new parent entity with the same UUID, but the existing children still point at the old empty entity id, so final validation fails. - Fix:
reverse-history-action!now expands:insert-blocksreverse:db/retractEntityoperations to include current descendant blocks before retracting the parent. This keeps the reverse phase subtree-consistent even if later child txs were dropped or are missing from the current pending slice. - Regression test:
frontend.worker.db-sync-test/apply-remote-txs-reverses-parent-insert-with-existing-child-without-orphaning-testfailed before the fix and passes after the fix. - Follow-up: add a reason to
:db-sync/drop-tx-idslogs so empty tx-data drops can be distinguished from other queue changes. - Stress verification: after rebuilding
static/db-worker-node.js,cli-sync-stress-5000-20260701-snapshot-last-error-1completed5001started ops, reached matching final checksum5790fdbc975a6b36on all three clients, passed finalgraph validateon all three clients, and had no event-logDB write failed with invalid dataor:block/parentvalidation failure. - Status: fixed by targeted test and fresh 5000-op stress verification.
Recovered remote apply failure after local tx snapshot drift
- Date: 2026-07-01
- Graph:
cli-sync-stress-5000-20260701-15 - Command:
LOGSEQ_BIN=/Users/tiensonqin/Codes/projects/logseq/static/logseq-cli.js node scripts/cli-concurrent-edit-stress.mjs --graph cli-sync-stress-5000-20260701-15 --config tmp/cli-sync-stress-multi-5000-20260701-15/cli.edn --root-dir tmp/cli-sync-stress-multi-5000-20260701-15/root --log-file tmp/cli-sync-stress-multi-5000-20260701-15/events.jsonl --clients 3 --concurrency 8 --max-ops 5000 --sync --offline --no-e2ee --timeout-ms 20000 --settle-attempts 60 --settle-ms 1000 - Log path:
tmp/cli-sync-stress-multi-5000-20260701-15/clients/client-3/root/graphs/cli-sync-stress-5000-20260701-15/db-worker-node-20260701.log - Symptom: client 3 logged a transient severe
:db-sync/apply-remote-txs-failedwhile applying remote txs with local changes. The failing tx was remotet=818,:outliner-op :rebase, which tried to update the order of block UUIDf0754dfd-6c36-4657-857a-181551579fdd; Datascript reportedNothing found for entity id [:block/uuid #uuid "f0754dfd-6c36-4657-857a-181551579fdd"]. - Evidence:
- Worker log line
568has the failed tx data: retract:block/order "b0mzz"and add:block/order "b0yV"forf0754dfd-6c36-4657-857a-181551579fdd. - Worker log line
591records:db-sync/apply-remote-txs-failedwith:has-local-changes? true,:remote-tx-count 36, and:local-tx-count 16. - Event log line
1643shows the same UUID was selected as the target of an earlier successful HTTPinsert-blocksoperation, so the remote tx referenced a block that should have existed or been repaired before applying the order update. - Client 3
client_opsshowed the block create tx at row397, a child insert at row412, and a later local delete at row633. - The failed worker log's
local-txslist contained rows617through632, but did not include row633. - Unlike
cli-sync-stress-5000-20260701-12, this run recovered: final recomputed/local/remote checksum was7c746bd7fb4ba9b3on all three clients, and finalgraph validatepassed on all three clients.
- Worker log line
- Root cause: remote apply used an inconsistent pair of snapshots. It read
pending-txsfirst and built repair/rebase context from that list, then laterbatch-transact-with-temp-conn!copied the live Datascript DB. A local delete off0754dfd-6c36-4657-857a-181551579fddwas applied and persisted as a pending tx after thepending-txssnapshot but before the temp DB snapshot. The temp DB therefore no longer had the block, but the apply attempt did not reverse that new delete because it was not inlocal-txs. Remote txt=818then tried to update:block/orderfor the missing block and failed. This is different from the earlier missing-block-after-local-reversal repair case: the repair preflight was not simply incomplete; it was based on a stale pending queue snapshot. - Fix: when remote apply fails and the current pending tx id list differs from the list captured for that apply attempt, the worker discards the stale attempt and restarts
apply-remote-txs!from fresh pending txs and the current DB. Snapshot-drift retries are treated as a retryable race; unrelated remote apply failures still surface normally. - Regression tests:
frontend.worker.db-sync-test/apply-remote-txs-rechecks-local-txs-when-local-delete-races-temp-snapshot-test: failed before the fix withNothing found for entity id [:block/uuid ...]; passes after the fix.frontend.worker.db-sync-test/apply-remote-txs-delays-retry-when-local-txs-keep-changing-test: forces more snapshot drifts than the immediate retry budget and verifies remote apply delays, retries from a fresh pending-tx snapshot, and does not report a remote apply failure.- Adjacent verification passed:
apply-remote-txs-local-delete-parent-remote-move-then-delete-parent-test,apply-remote-txs-overlap-out-of-order-parent-delete-then-move-repairs-test,apply-remote-txs-repairs-order-only-block-made-missing-by-local-reversal-test, andapply-remote-txs-delete-parent-with-child-without-local-changes-test.
- Stress verification: after rebuilding
static/db-worker-node.js,cli-sync-stress-5000-20260701-snapshot-last-error-1completed5001started ops, reached matching final checksum5790fdbc975a6b36on all three clients, and passed finalgraph validateon all three clients. Its event log had noapply-remote-txs-failed,sync-start-runtime-error, or error-level entries; the run did not produce db-worker log files, so worker-log-level severe entries are not separately asserted for this run. - Status: root cause fixed by targeted worker tests and verified by fresh 5000-op stress at event/final-state level.
Remote apply exhausted immediate retries while local txs kept changing
- Date: 2026-07-01
- Graph:
cli-sync-stress-5000-20260701-18 - Command:
LOGSEQ_BIN=/Users/tiensonqin/Codes/projects/logseq/static/logseq-cli.js node scripts/cli-concurrent-edit-stress.mjs --graph cli-sync-stress-5000-20260701-18 --config tmp/cli-sync-stress-multi-5000-20260701-18/cli.edn --root-dir tmp/cli-sync-stress-multi-5000-20260701-18/root --log-file tmp/cli-sync-stress-multi-5000-20260701-18/events.jsonl --clients 3 --concurrency 8 --max-ops 5000 --sync --offline --no-e2ee --timeout-ms 20000 --settle-attempts 60 --settle-ms 1000 - Symptom: the run completed and converged, but the primary worker log had a recovered severe
:db-sync/apply-remote-txs-failedat line131. The error waspending local tx snapshot changed during remote apply; the attempt had:remote-tx-count 5and:local-tx-count 23. - Evidence:
- Lines
95,107, and119intmp/cli-sync-stress-multi-5000-20260701-18/root/graphs/cli-sync-stress-5000-20260701-18/db-worker-node-20260701.logshow three immediate:db-sync/retry-remote-apply-after-local-tx-snapshot-driftwarnings. Each retry observed additional pending local tx ids. - Line
131then logged severe:db-sync/apply-remote-txs-failedbecause the fourth consecutive drift exceededmax-remote-apply-snapshot-retries. - The event log later showed final recomputed/local/remote checksum
3cce9543989a7855on all three clients and finalgraph validatepassed on all three clients. This proves the failure was recoverable, but still produced a false severe apply failure during normal concurrent editing.
- Lines
- Root cause: the first snapshot-drift fix only retried immediately and capped the in-call retry count at three. Under continuous CLI writes, remote apply could see a valid snapshot drift four times in a row. That is not a corrupt remote tx or invalid DB state; it just means local edits are still arriving while remote apply is trying to take a consistent pending-tx and DB snapshot.
- Fix: snapshot drift now remains a retryable path after the immediate retry budget. When the budget is exhausted, remote apply logs
:db-sync/delay-remote-apply-after-local-tx-snapshot-drift, yields briefly, and restarts from a fresh pending-tx snapshot instead of reporting:db-sync/apply-remote-txs-failed. Actual apply errors without pending snapshot drift still go through the severe failure/reporting path. - Regression test:
frontend.worker.db-sync-test/apply-remote-txs-delays-retry-when-local-txs-keep-changing-test. - Test evidence:
rtk bb dev:test -v frontend.worker.db-sync-test/apply-remote-txs-delays-retry-when-local-txs-keep-changing-test -v frontend.worker.db-sync-test/apply-remote-txs-rechecks-local-txs-when-local-delete-races-temp-snapshot-test -v frontend.worker.db-sync-test/apply-remote-txs-rechecks-local-txs-when-local-delete-races-temp-commit-test -v frontend.worker.db-sync-test/apply-remote-txs-repairs-order-only-block-made-missing-by-local-reversal-test -v frontend.worker.db-sync-test/apply-remote-txs-local-delete-parent-remote-move-then-delete-parent-test -v frontend.worker.db-sync-test/apply-remote-txs-overlap-out-of-order-parent-delete-then-move-repairs-test: 6 tests, 29 assertions, 0 failures. - Stress verification: after rebuilding
static/db-worker-node.js,cli-sync-stress-5000-20260701-snapshot-last-error-1completed5001started ops, reached matching final checksum5790fdbc975a6b36on all three clients, and passed finalgraph validateon all three clients. Its event log had nopending-tx-snapshot-changed,sync-start-runtime-error,apply-remote-txs-failed, or error-level entries. - Status: fixed by targeted test and fresh 5000-op stress verification.
Property batch remote apply referenced blocks already missing on another client
- Date: 2026-07-01
- Graph:
cli-sync-stress-5000-20260701-19 - Command:
LOGSEQ_BIN=/Users/tiensonqin/Codes/projects/logseq/static/logseq-cli.js node scripts/cli-concurrent-edit-stress.mjs --graph cli-sync-stress-5000-20260701-19 --config tmp/cli-sync-stress-multi-5000-20260701-19/cli.edn --root-dir tmp/cli-sync-stress-multi-5000-20260701-19/root --log-file tmp/cli-sync-stress-multi-5000-20260701-19/events.jsonl --clients 3 --concurrency 8 --max-ops 5000 --sync --offline --no-e2ee --timeout-ms 20000 --settle-attempts 60 --settle-ms 1000 - Symptom: the run completed
5001started ops, all three clients converged to checksumb82c6db876ec2c36, and finalgraph validatepassed, but client 3 logged a severe recovered:db-sync/apply-remote-txs-failed. - Evidence:
- Event log line
3488shows worker 8 seq 168 applyinghttp-batch-set-propertyto ids[1453,1398,1368]. tmp/cli-sync-stress-multi-5000-20260701-19/clients/client-3/root/graphs/cli-sync-stress-5000-20260701-19/db-worker-node-20260701.log, line76, shows the remote txt=1557failing withNothing found for entity id [:block/uuid #uuid "6b495b02-2a45-4bcc-82d6-ef3684e7053c"].- The same log line shows the failing tx adds
:block/refs,:user.property/cli-http-prop, and a property value child whose:block/parentis the same missing UUID. Line99records:has-local-changes? false,:remote-tx-count 41, and:local-tx-count 0, so this is not the pending snapshot drift retry path. - Client 2 also logged a stale reverse failure for a later
http-batch-set-propertypending tx, where reversing the batch tried to retract property value blocks and parent property refs for target blocks that no longer existed.
- Event log line
- Root cause: property batch txs can include side-effect datoms for several target blocks. Under concurrent delete/rebase, one client may receive a remote property batch after a target block has already been removed locally and is also absent from the server repair endpoint. Existing repair handles missing block lookup refs when the server can still return the block. Existing stale-drop logic handles missing refs only when the same remote batch later contains
:db/retractEntityfor that block. This case had neither condition: repair returned no block, and the tx still tried to add refs/properties and a property value child under the missing target, so Datascript aborted the whole remote batch before unrelated txs could apply. - Fix: remote tx application now carries the repair-requested missing block UUIDs into
transact-remote-txs!. After repair has had a chance to populate those blocks, any still-missing repair target that is not created by the current remaining remote batch is treated as stale. The sanitizer drops datoms directly targeting that stale block and drops newly-created side-effect blocks whose datoms point at the stale block, while preserving unrelated txs in the same remote batch. - Regression test:
frontend.worker.db-sync-test/apply-remote-txs-drops-stale-property-batch-side-effects-for-unrepaired-missing-target-test. - Test evidence:
rtk bb dev:test -v frontend.worker.db-sync-test/apply-remote-txs-drops-stale-property-batch-side-effects-for-unrepaired-missing-target-test -v frontend.worker.db-sync-test/apply-remote-txs-repairs-missing-block-lookup-ref-test -v frontend.worker.db-sync-test/apply-remote-txs-repairs-missing-block-ref-value-test -v frontend.worker.db-sync-test/apply-remote-txs-with-local-changes-repairs-missing-block-lookup-ref-test: 4 tests, 16 assertions, 0 failures. - Stress verification: after rebuilding
static/db-worker-node.js,cli-sync-stress-5000-20260701-20completed5001started ops, reached matching final checksumfc3492f6c370efe4on all three clients, and passed finalgraph validateon all three clients. Its event log had noapply-remote-txs-failed, no error-level entries, no failed/no-op events, and no fatal event. Worker logs had no:db-sync/apply-remote-txs-failed; the only severe entries were expected local HTTP stale-target exceptions forhttp-set-block-property, documented below. - Status: fixed by targeted test and fresh 5000-op stress verification at event/final-state and worker-log remote-apply level.
Local HTTP set-block-property raced with deleted targets
- Date: 2026-07-01
- Graph:
cli-sync-stress-5000-20260701-20 - Command:
LOGSEQ_BIN=/Users/tiensonqin/Codes/projects/logseq/static/logseq-cli.js node scripts/cli-concurrent-edit-stress.mjs --graph cli-sync-stress-5000-20260701-20 --config tmp/cli-sync-stress-multi-5000-20260701-20/cli.edn --root-dir tmp/cli-sync-stress-multi-5000-20260701-20/root --log-file tmp/cli-sync-stress-multi-5000-20260701-20/events.jsonl --clients 3 --concurrency 8 --max-ops 5000 --sync --offline --no-e2ee --timeout-ms 20000 --settle-attempts 60 --settle-ms 1000 - Symptom: the stress event log completed successfully, but client worker logs contained severe
:db-worker-node-invoke-failedentries for local HTTPthread-api/apply-outliner-opsrequests. The HTTP response wasSet block property failed: block or property doesn't exist. - Evidence:
- Event log lines
920,2627, and11809classify the correspondinghttp-set-block-propertycalls asoutcome:"race-conflict",level:"info", status500. - The three target block UUIDs were
9a7111f9-0c4f-4876-ab46-e779117b459f,9136b835-8f30-4557-a24a-8ef94f8a1abf, and6a451423-a7ac-4b79-9a20-ba87efb04d81. - Final settle on all clients returned recomputed/local/remote checksum
fc3492f6c370efe4, and finalgraph validatepassed on all clients. - The event log had no
level:"error", nooutcome:"failed", nooutcome:"no-op", and no fatal event. Worker logs had no:db-sync/apply-remote-txs-failed.
- Event log lines
- Root cause: the stress harness intentionally chooses IDs from a shared live block pool while concurrent workers delete and recycle blocks. A block can be selected for local
set-block-property, then deleted before the HTTP outliner op reaches the worker. In that case the local mutation is correctly rejected because its target no longer exists. This does not indicate remote tx corruption or sync divergence. - Fix: no product sync fix is required for this case. The harness already classifies the response as an expected
race-conflict, keeps the run alive, and validates final convergence. Worker-log review for stress runs must distinguish local HTTP handler exceptions for expected stale-target operations from sync worker remote-apply failures. - Regression test or stress verification:
cli-sync-stress-5000-20260701-20completed5001started ops with matching checksums and graph validation passing on all three clients despite these expected local race conflicts. - Status: documented expected race signal; not counted as a failed sync case unless it is accompanied by final checksum mismatch, graph validation failure, fatal event, failed/no-op event, or
:db-sync/apply-remote-txs-failed.
Retryable pending snapshot drift polluted last-error
- Date: 2026-07-01
- Graph:
cli-sync-stress-5000-20260701-cas-rebase-1 - Command:
LOGSEQ_BIN=/Users/tiensonqin/Codes/projects/logseq/static/logseq-cli.js node scripts/cli-concurrent-edit-stress.mjs --graph cli-sync-stress-5000-20260701-cas-rebase-1 --config tmp/cli-sync-stress-cas-rebase-5000-1/cli.edn --root-dir tmp/cli-sync-stress-cas-rebase-5000-1/root --log-file tmp/cli-sync-stress-cas-rebase-5000-1/events.jsonl --clients 3 --concurrency 8 --max-ops 5000 --sync --offline --no-e2ee --timeout-ms 20000 --settle-attempts 60 --settle-ms 1000 - Symptom: the run completed
5001started ops and final validation passed on all three clients, but duringmulti-client-offline-rebase,sync starton client 3 failed withsync-start-runtime-errorbecausesync statuscontainedlast-errorcodepending-tx-snapshot-changed. - Evidence:
- Event log around
2026-07-01T12:32:47Zshowssync start reached open websocket but runtime sync error is present. - The
last-errorpayload had:code :pending-tx-snapshot-changed, a capturedlocal-tx-idslist, and acurrent-local-tx-idslist with one extra pending tx id. - Final settle later succeeded: all clients recomputed local/remote checksum
e3da05c1ead3bf6b, and finalgraph validatepassed on all three clients.
- Event log around
- Root cause:
:pending-tx-snapshot-changedis an internal retry/control signal, not a durable sync error. The previous retry condition re-read the mutable pending queue in the catch path. That handled ordinary missing-entity errors while the queue still differed, but it could expose the control exception as a real error if the queue changed again before the catch path or ifsync startinspectedlast-errorbefore the retry cleared it. - Fix: remote apply now treats
:pending-tx-snapshot-changeditself as retryable, regardless of what a second pending-queue read returns. It still also retries non-control apply errors when the pending tx snapshot is currently different, preserving the original missing-entity retry path. - Regression tests:
frontend.worker.db-sync-test/apply-remote-txs-retries-snapshot-drift-even-if-pending-list-stabilizes-testfailed before the fix by surfacingpending local tx snapshot changed during remote apply; it passes after the fix.- Adjacent retry tests passed:
apply-remote-txs-rechecks-local-txs-when-local-delete-races-temp-snapshot-test,apply-remote-txs-rechecks-local-txs-when-local-delete-races-temp-commit-test, andapply-remote-txs-delays-retry-when-local-txs-keep-changing-test.
- Stress verification: after rebuilding
static/db-worker-node.js,cli-sync-stress-5000-20260701-snapshot-last-error-1completed5001started ops, reached matching final checksum5790fdbc975a6b36on all three clients, passed finalgraph validateon all three clients, and had no event-logpending-tx-snapshot-changedorsync-start-runtime-errorentries. - Status: fixed by targeted tests and fresh 5000-op stress verification.
Remote apply committed over a local page delete before permanent recycle delete
- Date: 2026-07-01
- Graph:
cli-sync-stress-5000-20260701-17 - Command:
LOGSEQ_BIN=/Users/tiensonqin/Codes/projects/logseq/static/logseq-cli.js node scripts/cli-concurrent-edit-stress.mjs --graph cli-sync-stress-5000-20260701-17 --config tmp/cli-sync-stress-multi-5000-20260701-17/cli.edn --root-dir tmp/cli-sync-stress-multi-5000-20260701-17/root --log-file tmp/cli-sync-stress-multi-5000-20260701-17/events.jsonl --clients 3 --concurrency 8 --max-ops 5000 --sync --offline --no-e2ee --timeout-ms 20000 --settle-attempts 60 --settle-ms 1000 - Symptom: the run was interrupted after
1498started ops becausehttp-recycle-delete-pagephasepermanent-deletereturned HTTP 200 with{"ok":true,"resultTransit":"[\"~#'\",null]"}for page UUID6a450134-0e3d-4025-ae1f-b802dab67185. - Evidence:
- Event log line
3463created pageCLI HTTP Recycle stress-1782906831598 177. - Line
3495applied rawdelete-pageto UUID6a450134-0e3d-4025-ae1f-b802dab67185and returned ok. - Line
3500applied rawrecycle-delete-permanentlyto the same UUID and gotresultTransit null. - A post-stop query of the same client graph found the page still present with no
:logseq.property/deleted-at, so the soft delete had been lost before permanent delete ran. - The worker log shows sync reconnect/remote-apply activity in the same window, including
pending-txs-count 15at2026-07-01T11:59:48.677Z. - The same run also showed a harness weakness:
http-recycle-delete-pagegenerated page titles fromrunId + seqonly, and different workers produced duplicate titles for sequences68,85, and110.
- Event log line
- Root cause: remote apply with local changes protected only the exception path from pending-local snapshot drift. It captured pending local txs, ran remote apply/rebase in a temp conn, and could then commit that temp result to the live conn even if a new local tx was added after the snapshot and before the final commit. In this case a local
delete-pagetx was applied after the remote-apply snapshot, then a successful temp remote apply committed an older DB view over it.recycle-delete-permanentlycorrectly returned nil because the page was no longer recycled. Separately, sequence-only stress page titles made raw page operations vulnerable to name lookup ambiguity under concurrent workers. - Fix:
logseq.db/batch-transact-with-temp-conn!now accepts a:before-commithook that runs after temp work and before live conn commit.frontend.worker.sync.apply-txs/apply-remote-tx-with-local-changes!uses that hook to abort and retry remote apply when the pending local tx id list changed since the snapshot, before the temp result can overwrite the live conn.- The stress harness now uses operation-owned unique page titles for raw create-page, delete/restore-page, and recycle/delete-page operations.
- Regression tests:
frontend.worker.db-sync-test/apply-remote-txs-rechecks-local-txs-when-local-delete-races-temp-commit-test.logseq.db-test/batch-transact-with-temp-conn-before-commit-can-abort-live-commit-test.- JavaScript harness test
raw page delete/restore uses unique operation-owned page titlescovers uniqueness for repeated worker/sequence inputs.
- Test evidence:
rtk bb dev:test -v frontend.worker.db-sync-test/apply-remote-txs-delays-retry-when-local-txs-keep-changing-test -v frontend.worker.db-sync-test/apply-remote-txs-rechecks-local-txs-when-local-delete-races-temp-snapshot-test -v frontend.worker.db-sync-test/apply-remote-txs-rechecks-local-txs-when-local-delete-races-temp-commit-test -v frontend.worker.db-sync-test/apply-remote-txs-repairs-order-only-block-made-missing-by-local-reversal-test -v frontend.worker.db-sync-test/apply-remote-txs-local-delete-parent-remote-move-then-delete-parent-test -v frontend.worker.db-sync-test/apply-remote-txs-overlap-out-of-order-parent-delete-then-move-repairs-test: 6 tests, 29 assertions, 0 failures.rtk pnpm --dir deps/db test-v logseq.db-test/batch-transact-with-temp-conn-before-commit-can-abort-live-commit-test logseq.db-test/batch-transact-with-temp-conn-preserves-cardinality-one-schema-test logseq.db-test/batch-transact-with-temp-conn-preserves-retracts-test: deps/db suite completed, 115 tests, 420 assertions, 0 failures.rtk node --test scripts/cli-concurrent-edit-stress.test.mjs scripts/cli-sync-stress-workflow.test.mjs: 30 tests, 0 failures.
- Stress verification: after rebuilding
static/db-worker-node.js,cli-sync-stress-5000-20260701-snapshot-last-error-1completed5001started ops, reached matching final checksum5790fdbc975a6b36on all three clients, passed finalgraph validateon all three clients, and had no event-loghttp-recycle-delete-pagenil/false failure,sync-start-runtime-error, orpending-tx-snapshot-changedentry. - Status: root cause fixed by targeted tests and fresh 5000-op stress verification.
http-delete-restore-page reused mutable shared page targets
- Date: 2026-07-01
- Graphs:
cli-sync-stress-1000-20260701-2cli-sync-stress-5000-20260701-1cli-sync-stress-5000-20260701-8cli-sync-stress-assert-20260701-1cli-sync-stress-5000-20260701-13cli-sync-stress-10000-20260701-1cli-sync-stress-5000-20260701-15cli-sync-stress-5000-20260701-16
- Log examples:
tmp/cli-sync-stress-multi-1000-20260701-2/events.jsonl, line859tmp/cli-sync-stress-multi-5000-20260701-1/events.jsonl, line991tmp/cli-sync-stress-multi-5000-20260701-8/events.jsonl, line2154tmp/cli-sync-stress-assert-20260701-1/events.jsonl, examples around2026-07-01T09:14:19Z,2026-07-01T09:14:33Z,2026-07-01T09:16:02Z, and2026-07-01T09:17:24Ztmp/cli-sync-stress-multi-5000-20260701-13/events.jsonl, lines3388,5869,8289, and11521tmp/cli-sync-stress-multi-10000-20260701-1/events.jsonl, lines3680,5095,5741, and6407tmp/cli-sync-stress-multi-5000-20260701-15/events.jsonl, lines1312,3090,4340, and15852tmp/cli-sync-stress-multi-5000-20260701-16/events.jsonl, line7213
- Symptom:
thread-api/apply-outliner-opsreturns HTTP 200 with{"ok":true,"resultTransit":"[\"~#'\",false]"}forhttp-delete-restore-pagephasedelete. - Current evidence:
- Earlier 1000-op, 5000-op, assertion 5000-op, and 10000-op runs completed with matching checksums and final graph validation, so this no-op alone has not reproduced sync divergence.
- In
cli-sync-stress-5000-20260701-16, the run failed fast on the no-op because the stress harness started requiring truthy raw apply results. The same pageCLI Concurrent Stress page 2was repeatedly selected as a mutable shared page target. Line7059deleted it through CLIpage-delete-restore, line7071restored it, line7114hit a concurrentrecycled-pagerace while creating blocks on it, and line7213then got the raw HTTPdelete-pageresultfalsefor page UUID6a44fc1f-ef7f-4085-8449-1adfbf325b1b.
- Root cause: the stress harness used
mutablePage(state)for rawhttp-delete-restore-page. That let multiple workers delete/restore the same stable page concurrently while other workers were also creating or moving blocks on the same page.delete-pagecan correctly return false when the selected page is already recycled or otherwise not a valid deletion target at apply time, so the harness was not isolating the raw outliner op it was trying to verify. - Fix:
http-delete-restore-pagenow creates a unique operation-owned page through rawcreate-page, resolves that page UUID, and then applies rawdelete-pageandrestore-recycledto that UUID. The operation still exercises create/delete/restore sync traffic, but a falsedelete-pageresult is no longer hidden by shared-page target races. - Regression test:
scripts/cli-concurrent-edit-stress.test.mjscoversuniqueOperationPageTitle, including repeated calls with the same worker and sequence. The full JavaScript harness test command now passes with 30 tests. - Stress verification:
cli-sync-stress-5000-20260701-18completed5001started ops with nohttp-delete-restore-pagefalse/no-op events, final recomputed/local/remote checksum3cce9543989a7855on all three clients, and finalgraph validatepassed on all three clients. A separate remote-apply retry-budget issue was found in the same run and is tracked above. - Status: fixed in the stress harness and verified by fresh 5000-op stress for this operation class; 10000-op stress still pending.
Stress retry reused an already-invalid graph root
- Date: 2026-07-01
- Graph:
cli-sync-stress-5000-20260701-2 - Command:
LOGSEQ_BIN=static/logseq-cli.js node scripts/cli-concurrent-edit-stress.mjs --graph cli-sync-stress-5000-20260701-2 --config tmp/cli-sync-stress-multi-5000-20260701-2/cli.edn --root-dir tmp/cli-sync-stress-multi-5000-20260701-2/root --log-file tmp/cli-sync-stress-multi-5000-20260701-2/events.jsonl --clients 3 --concurrency 8 --max-ops 5000 --sync --offline --no-e2ee --timeout-ms 20000 --settle-attempts 60 --settle-ms 1000 - Symptom: the retry failed at
sync startwith a stalelast-errorreporting invalid reverse tx data formove-blocks, including multi-valued:block/parentand:block/order. - Evidence:
tmp/cli-sync-stress-multi-5000-20260701-2/events.jsonlcontains an earlier run starting at2026-07-01T07:11:50Z, before the retry at2026-07-01T08:29:35Z.graph validateon that root reports the graph is already invalid, with 25 invalid entities.- The failing
sync startreusedlocal-tx 65,pending-local 65, andpending-server 99from that existing graph state instead of starting from an empty post-fix graph.
- Root cause: the verification command reused a graph/root/log path from an earlier failed run. The retry therefore exercised stale pre-fix graph state and stale sync error state, not the newly rebuilt sync code.
- Fix: long-run verification must use a unique graph name and root directory, and the root must be checked for absence before treating the run as fresh.
- Regression test or stress verification: not a product-code regression. The next valid evidence must come from a new graph/root, starting from no existing local graph files.
- Status: invalid test run; superseded by the next fresh 5000-op run.
Temp rebase conn lost Datascript schema for cardinality-one replacement
- Date: 2026-07-01
- Graph: observed while investigating invalid sync-start state in
cli-sync-stress-5000-20260701-2; the graph/root was later classified as contaminated test evidence, but the helper bug was real and independently reproduced. - Symptom: applying local pending reverse txs during remote rebase could produce invalid entities with multiple
:block/parentor:block/ordervalues. Example last-error:DB write failed with invalid data,tx-meta {:outliner-op "move-blocks" :reverse? true}, with validation errors showing:block/parent [264 222]and:block/order ["a6" "a0"]. - Root cause:
logseq.db/batch-transact-with-temp-conn!built its temporary connection withd/create-connand then swapped in the source:db. The temp connection could read the source DB, but its connection metadata did not preserve the source Datascript schema. Inner temp transacts therefore did not reliably emit replacement retractions for cardinality-one attrs, so the final replay into the live conn could accumulate values for attrs such as:block/orderand:block/parent. - Fix: the temp connection constructor now creates the isolated conn with
(:schema db)before swapping in the source db state. This preserves Datascript cardinality and uniqueness behavior while keeping the temp conn isolated from storage writes. - Regression tests:
logseq.db-test/batch-transact-with-temp-conn-preserves-cardinality-one-schema-testfrontend.worker.db-sync-test/temp-conn-batch-preserves-cardinality-one-schema-test- Rebase adjacency still passes:
frontend.worker.db-sync-test/rebase-local-insert-then-save-keeps-cardinality-one-values-test,frontend.worker.db-sync-test/apply-remote-txs-skips-stale-move-before-later-delete-test,frontend.worker.db-sync-test/apply-remote-txs-skips-stale-move-to-target-before-later-target-delete-test,frontend.worker.db-sync-test/apply-remote-txs-with-local-changes-rejects-invalid-final-rebase-test.
- Test evidence:
rtk pnpm --dir deps/db test-v logseq.db-test/batch-transact-with-temp-conn-preserves-cardinality-one-schema-testcompleted the deps/db suite: 114 tests, 418 assertions, 0 failures.rtk bb dev:test -v frontend.worker.db-sync-test/temp-conn-batch-preserves-cardinality-one-schema-test ...completed 5 worker tests, 15 assertions, 0 failures.
- Post-fix stress verification: fresh 5000-op and 10000-op stress runs completed with final graph validation passing on all clients and no cardinality-one validation errors.
- Status: fixed and verified in targeted tests plus fresh stress runs.
Recent db-test sync-stuck issue cluster
- Date checked: 2026-07-01
- Issues:
logseq/db-test#937: existing browser graphs do not sync; console reportsInvalid local txwithlocal-tx nil.logseq/db-test#947: browser reports0 pending server changeswhile desktop and CLI changes are already on the server.logseq/db-test#969: after suspend/resume, the app is online but RTC is stopped withrtc-state :close,pending-local-ops 1, andlocal-tx == remote-tx; clickingStart Syncresumes sync.logseq/db-test#898: graph stays yellow and only recovers after deleting the local graph and re-downloading.logseq/db-test#890: graph stays inPreparing; opening from remote graphs works but no sync indicator appears.
Repro path: missing client-ops local-tx
- Target symptom:
Invalid local txon serverhello, or a silentdb-sync/start-skippedbecauseclient-op-ready?is false. - State to create: graph DB and client-ops DB are both open, but
sync_meta.local-txis missing from the client-ops DB. - Why this matches the issues: existing local graphs affected by old cache/migration state can have remote graph ids and pending local rows, while
local-txis absent. Missinglocal-txmust not be treated as0, because that would force the client to pull too many server txs from the beginning. - Existing fix:
:thread-api/db-sync-startopens DBs before starting sync, andsync/start!skips with:client-op-not-readyuntil client-op metadata has a real integerlocal-tx. - Regression test:
frontend.worker.sync.restart-test/start-skips-when-client-op-local-tx-is-missing-test. - Expected fixed behavior: no websocket connection is opened when
local-txis missing, and no code initializes missinglocal-txto0outside the explicit new-remote-graph/upload paths.
Repro path: stale RTC after resume
- Target symptom: online app with
rtc-state :close, pending local changes, and no automatic retry until manualStart Sync. - State to create: current RTC client still targets the active repo/graph, but its websocket is already closed or stale after sleep/offline/resume.
- Relevant issue evidence:
logseq/db-test#969reportspending-local-ops 1,local-tx 1244,remote-tx 1244,rtc-state :close;logseq/db-test#780reports stale websocket timeout after network returns. - Regression tests:
frontend.handler.db-based.rtc-flows-test/resume-restart-events-do-not-depend-on-cached-rtc-lock-testfrontend.worker.sync.restart-test/start-reconnects-closed-ws-with-stale-open-state-testfrontend.worker.sync.restart-test/stale-loop-marks-non-open-ws-closed-testfrontend.worker.sync.restart-test/ws-close-clears-inflight-before-reconnect-test
- Expected fixed behavior: network-visible/resume triggers can restart RTC, and stale/closed websockets clear inflight state, broadcast
:closed, and schedule reconnect instead of leaving the graph permanently stopped.