AtlatestRepositoryfolio
1
;;; A mutation remains serialized through its delayed index flush.2
(import (sigil test)3
(sigil fs)4
(sigil path)5
(sigil string)6
(sigil async)7
(sigil channels)8
(sigil time)9
(sigil sqlite)10
(sigil mcp server)11
(sigil mcp protocol)12
(folio store)13
(folio index)14
(folio tools))16
(test-group "whole writer serialization"17
(test "a second mutation waits until the first index flush finishes"18
(call-with-temp-directory19
(lambda (root)20
(let* ((store (make-folio-store root))21
(file (path-join (store-notes-dir store) "writer.md"))22
(_ (write-file-string file "# Writer\n"))23
(idx (make-folio-index store))24
(_ (index-census-tick! idx))25
(server (mcp-server name: "writer-test"))26
(ready (make-channel 1))27
(release (make-channel 1))28
(done (make-channel 2))29
(first-visible? #f)30
(second-waited? #f))31
(define (append! id marker)32
(let ((reply (mcp-server-handle-message server33
(jsonrpc-request id: id method: "tools/call"34
params: (dict name: "folio/note-edit"35
arguments: (dict name: "writer" append: marker))))))36
(channel-send done reply)))37
(register-folio-tools! server store idx)38
(with-async39
(go40
(with-index-transaction idx41
(lambda ()42
(channel-send ready #t)43
(channel-receive release))))44
(go45
(channel-receive ready)46
(go (append! 1 "first-marker\n"))47
(let wait ((attempt 0))48
(unless (or (string-contains? (read-file-string file) "first-marker")49
(= attempt 200))50
(sleep 0.01)51
(wait (+ attempt 1))))52
(set! first-visible? (string-contains? (read-file-string file) "first-marker"))53
(go (append! 2 "second-marker\n"))54
(sleep 0.1)55
(set! second-waited? (not (string-contains? (read-file-string file) "second-marker")))56
(channel-send release #t)57
(assert-true (jsonrpc-response? (channel-receive done)))58
(assert-true (jsonrpc-response? (channel-receive done)))))59
(display (format "WRITER gate first-visible=~a second-waited=~a\n"60
first-visible? second-waited?))61
(assert-true first-visible?)62
(assert-true second-waited?)63
(let ((content (read-file-string file)))64
(assert-true (string-contains? content "first-marker"))65
(assert-true (string-contains? content "second-marker")))66
(sqlite-close (folio-index-db idx)))))))