AtlatestRepositoryfolio

folio / tree / testtest-http-read-index.sgl

1;;; HTTP reads use committed index rows while a writer owns its transaction.
2(import (sigil test)
3 (sigil fs)
4 (sigil path)
5 (sigil json)
6 (sigil string)
7 (sigil sqlite)
8 (sigil mcp server)
9 (sigil mcp protocol)
10 (folio store)
11 (folio index)
12 (folio tools))
14(define (call-tool server name args)
15 (let* ((reply
16 (json-decode
17 (response->json
18 (mcp-server-handle-message server
19 (jsonrpc-request id: 1 method: "tools/call"
20 params: (dict name: name arguments: args))))))
21 (content (dict-ref (dict-ref reply result:) content:)))
22 (dict-ref (array-ref content 0) text:)))
24(test-group "separate read index"
25 (test "tool reads see committed rows during a writer transaction and refresh after commit"
26 (call-with-temp-directory
27 (lambda (root)
28 (let* ((store (make-folio-store root))
29 (notes (store-notes-dir store)))
30 (write-file-string (path-join notes "a.md")
31 "---\nlast-updated: 2026-01-01\n---\n# A\n[[b]]\n")
32 (write-file-string (path-join notes "b.md")
33 "---\nlast-updated: 2026-01-02\n---\n# B\n")
34 (let* ((writer (make-folio-index store))
35 (_ (index-census-tick! writer))
36 (reader (make-folio-index store))
37 (server (mcp-server name: "read-index-test")))
38 (register-folio-tools! server store writer read-index: reader)
39 (assert-true (string-contains?
40 (call-tool server "folio/note-links" (dict name: "b")) "← a"))
41 (with-index-transaction writer
42 (lambda ()
43 (assert-true (sqlite-run (folio-index-db writer)
44 "UPDATE notes_meta SET last_updated = ? WHERE name = ?"
45 "2099-12-31" "a"))
46 (assert-true (sqlite-run (folio-index-db writer)
47 "DELETE FROM note_links WHERE target = ?" "b"))
48 (let ((recent? (string-contains?
49 (call-tool server "folio/status" (dict))
50 "## Recent Notes\n\n b\n a"))
51 (backlink? (string-contains?
52 (call-tool server "folio/note-links" (dict name: "b")) "← a"))
53 (search? (equal? "No notes found."
54 (call-tool server "folio/notes" (dict since: "2099-01-01")))))
55 (display (format "READ isolation committed-recent=~a committed-backlink=~a committed-search=~a\n"
56 recent? backlink? search?))
57 (assert-true recent?)
58 (assert-true backlink?)
59 (assert-true search?))))
60 (assert-true (string-contains?
61 (call-tool server "folio/status" (dict))
62 "## Recent Notes\n\n a\n b"))
63 (assert-false (string-contains?
64 (call-tool server "folio/note-links" (dict name: "b")) "← a"))
65 (assert-true (string-contains?
66 (call-tool server "folio/notes" (dict since: "2099-01-01")) " a"))
67 (sqlite-close (folio-index-db reader))
68 (sqlite-close (folio-index-db writer))))))))