1a7a8f6f22
QuestDB has no multi-table transaction, so a HistoryUpdate writes its trail row before the sample change. A failed or crashed change left an orphan trail row that modified reads served as a change that happened, and a trail INSERT re-sent after a client timeout duplicated (the table had no key). - sample_modified gains `pending` and DEDUP UPSERT KEYS(ts, tag, modified_id). The trail row is written pending; after the change lands the same row is re-upserted pending = false (the applied marker). - A transient trail INSERT failure is re-sent once with the same ids; a first attempt that did apply converges on the key. - ReadModifiedAsync serves a pending row only when it is the latest trail row at its time and the sample there was written at or after the modification (a crash between change and marker). The orphan of a change that never landed, typically followed by the client's retry, is dropped. ASOF JOIN over the window's samples of one tag; the resume filter sits outside the window function so it never cuts a time's partition. - The bootstrapper migrates an older trail (ADD COLUMN pending, DEDUP ENABLE) and waits for it to apply (bounded 10 s); old rows read pending = false and stay visible. Until applied, or with AutoCreateSchema=false, the old format is used. Rebased from the unpushed remed/lane-H2 branch (originally authored 2026-10-22 in session_01Ub9hGmYLQvn9XETzw7CMsT) onto current master. Claude-Session: https://claude.ai/code/session_01GT67AEHd2Acv1YPwGfXEoV