AtlatestRepositoryfolio

folio / tree / testtest-extent-syntactic.sgl

1;;; RED ARM for the extent-syntactic redesign (t-a6ba).
2;;;
3;;; A multi-line capture must round-trip: added, listed, moved, completed, and
4;;; read back identically. This is the case that has never worked: on the old
5;;; writer the {id:} metadata landed on the capture's LAST line, the
6;;; line-oriented parser saw only the headless first line, and `backfill-ids!`
7;;; then minted a phantom id onto it. One capture became two tasks, one of them
8;;; a phantom, and the real body went invisible while `folio_status` reported
9;;; the inbox empty. Seven items were buried this way between April and August
10;;; 2026; the seventh (t-a979a6) hid a live CI blocker.
11;;;
12;;; The fixture below is built from the ACTUAL seventh burial: the same
13;;; paragraph structure as the t-a979a6 capture recovered from ~/Ops git
14;;; history (3d96327f~1:folio/inbox.md), abridged but shape-identical —
15;;; a first line, blank-separated numbered paragraphs, a closing cross-ref
16;;; line. These tests were committed and demonstrated FAILING against the
17;;; pre-redesign writer/parser before any implementation code was written.
19(import (sigil test)
20 (sigil struct)
21 (sigil string)
22 (sigil list)
23 (sigil dict)
24 (sigil fs)
25 (sigil path)
26 (folio store)
27 (folio task)
28 (folio id)
29 (folio inbox)
30 (folio project)
31 (folio tools))
33;; The t-a979a6 burial shape, abridged. Multi-line, paragraphs separated by
34;; blank lines — exactly what folio_inbox-add receives for a real capture.
35(define burial-text
36 (string-join
37 (list
38 "TWO OBLIGATIONS ON WHOEVER CLOSES THIS, both in jobs/enclave.run:"
39 ""
40 "(1) RE-MEASURE AND TIGHTEN THE JOB TIMEOUT. The 2400s margin covers a"
41 "step that has never completed, and that reason is spent once this lands."
42 ""
43 "(2) REMOVE THE XFAIL EXEMPTION. It will XPASS loudly when this starts"
44 "passing — that XPASS is the signal to delete the exemption."
45 ""
46 "See tasks/kiln-enclave-job-with-pwa-gates and t-c3d0b1 for the family.")
47 "\n"))
49;; Count raw occurrences of a needle in a string.
50(define (count-occurrences hay needle)
51 (let loop ((from 0) (n 0))
52 (let ((hit (string-find hay needle from)))
53 (if hit
54 (loop (+ hit (string-length needle)) (+ n 1))
55 n))))
57(test-group "extent-syntactic red arm: multi-line capture round-trips"
59 (test "added then read back: one task, the SUPPLIED id, the FULL text"
60 (call-with-temp-directory
61 (lambda (dir)
62 (let* ((store (make-folio-store dir))
63 (added (inbox-add! store burial-text '((id . "t-a979a6"))))
64 (tasks (read-inbox store)))
65 (assert-equal 1 (length tasks))
66 (assert-equal "t-a979a6" (folio-task-id (car tasks)))
67 (assert-equal burial-text (folio-task-text (car tasks)))))))
69 (test "the read path's backfill does not mint a phantom id onto the capture"
70 (call-with-temp-directory
71 (lambda (dir)
72 (let* ((store (make-folio-store dir)))
73 (inbox-add! store burial-text '((id . "t-a979a6")))
74 ;; the exact mechanism of all ten burials: backfill runs on read
75 (backfill-ids! (store-inbox-path store))
76 (let ((content (read-file-string (store-inbox-path store))))
77 ;; exactly ONE id on disk — a second one is the phantom
78 (assert-equal 1 (count-occurrences content "id: t-")))))))
80 (test "moved to a project: the whole item travels, nothing stays behind"
81 (call-with-temp-directory
82 (lambda (dir)
83 (let* ((store (make-folio-store dir))
84 (file (project-create! store "Kiln" "CI" #f)))
85 (inbox-add! store burial-text '((id . "t-a979a6")))
86 (let ((result (move-task-in-store! store "t-a979a6" "kiln")))
87 (assert-true (string-contains? result "Moved"))
88 ;; the inbox no longer contains ANY fragment of the capture
89 (let ((inbox-content (read-file-string (store-inbox-path store))))
90 (assert-false (string-contains? inbox-content "OBLIGATIONS"))
91 (assert-false (string-contains? inbox-content "XFAIL"))
92 (assert-false (string-contains? inbox-content "t-a979a6")))
93 ;; and the project holds the identical task
94 (let ((landed (folio-project-tasks (read-project file))))
95 (assert-equal 1 (length landed))
96 (assert-equal "t-a979a6" (folio-task-id (car landed)))
97 (assert-equal burial-text (folio-task-text (car landed)))))))))
99 (test "completed in place: done flips, id and full text intact"
100 (call-with-temp-directory
101 (lambda (dir)
102 (let* ((store (make-folio-store dir)))
103 (inbox-add! store burial-text '((id . "t-a979a6")))
104 (complete-task-in-store! store "t-a979a6")
105 (let ((tasks (read-inbox store)))
106 (assert-equal 1 (length tasks))
107 (assert-true (folio-task-done? (car tasks)))
108 (assert-equal "t-a979a6" (folio-task-id (car tasks)))
109 (assert-equal burial-text (folio-task-text (car tasks))))))))
111 (test "a body containing checkbox-looking lines stays ONE item"
112 (call-with-temp-directory
113 (lambda (dir)
114 (let* ((store (make-folio-store dir))
115 (text (string-join
116 (list "Close out the enclave job"
117 "Acceptance criteria:"
118 "- [ ] timeout re-measured"
119 "- [ ] xfail exemption removed")
120 "\n")))
121 (inbox-add! store text '((id . "t-c3d0b1")))
122 (let ((tasks (read-inbox store)))
123 (assert-equal 1 (length tasks))
124 (assert-equal "t-c3d0b1" (folio-task-id (car tasks)))
125 (assert-equal text (folio-task-text (car tasks))))))))
127 (test "visible count agrees with raw id count on a mixed corpus"
128 (call-with-temp-directory
129 (lambda (dir)
130 (let* ((store (make-folio-store dir)))
131 (inbox-add! store "plain one-liner" '((id . "t-000001")))
132 (inbox-add! store burial-text '((id . "t-a979a6")))
133 (inbox-add! store "another one-liner" '((id . "t-000002")))
134 (let* ((tasks (read-inbox store))
135 (content (read-file-string (store-inbox-path store)))
136 (raw (count-occurrences content "id: t-")))
137 ;; the acceptance criterion: folio's count and grep's count agree
138 (assert-equal raw (length tasks))
139 (assert-equal 3 (length tasks))
140 ;; and agree about WHICH ids, not merely how many: a count can
141 ;; match while a headless burial is counted under a phantom id
142 ;; (this arm was GREEN on the pre-redesign code when it compared
143 ;; counts alone — the ambiguous-green trap, made discriminating)
144 (assert-equal '("t-000001" "t-a979a6" "t-000002")
145 (map folio-task-id tasks))))))))