Artifact d672f492a49136cbbae195fb47d7b7920da42324708ef1bb1e3c1a1d36aa5369:
- File
internal/index/branchclosed_test.go
— part of check-in
[d6bf4e65b3]
at
2026-08-31 15:24:54
on branch trunk
— fold the branch summary instead of deriving it per request
branch.list grouped every check-in in the repository on every request: ~150ms in sqlite on tcl, 460-850ms through the driver, on a page whose budget is 500ms. A LIMIT could not help — the grouping happens before the limit applies. Same remedy as the ticket table: fold once when the shape changes, read by index. Refreshed in both fold paths, which the parity test insisted on. (user: quarry, size: 3509) [annotate] [blame] [check-ins using]
package index import "testing" // tag records a tag on a check-in, the way an artifact fold would. func tag(t *testing.T, ix *Index, checkin, name, sign, date string) { t.Helper() // src is the artifact carrying the T card; one per (checkin, name) // here, since these fixtures never re-tag the same pair. if _, err := ix.db.Exec(`INSERT OR REPLACE INTO checkin_tag (src, date, checkin, name, sign, value) VALUES (?, ?, ?, ?, ?, '')`, "t-"+checkin+"-"+name+"-"+sign, date, checkin, name, sign); err != nil { t.Fatal(err) } } // foldBranches runs the derivation the ingest fold runs at the end of // each batch. These fixtures write checkin rows directly, so they have // to trigger it themselves — production does it once per ingest. func foldBranches(t *testing.T, ix *Index) { t.Helper() tx, err := ix.db.Begin() if err != nil { t.Fatal(err) } if err := refreshBranches(tx); err != nil { t.Fatal(err) } if err := tx.Commit(); err != nil { t.Fatal(err) } } func closedSet(t *testing.T, ix *Index) map[string]bool { t.Helper() foldBranches(t, ix) bs, err := ix.Branches() if err != nil { t.Fatal(err) } out := map[string]bool{} for _, b := range bs { out[b.Name] = b.Closed } return out } // Closing a branch is a question about its TIP, and fossil writes the // answer three different ways. Reading only a `+` on the tip reported // five of this repository's own closed branches as open, which put them // all back in the timeline's branch selector. func TestClosedBranchesCoverEveryTagShape(t *testing.T) { ix := openIndex(t) // A one-check-in close: the tag sits on the tip itself. ci(t, ix, "a1", "plain-plus", "2026-01-01T10:00:00", "work") tag(t, ix, "a1", "closed", "+", "2026-01-01T10:00:00") // A PROPAGATING close on the tip. This is the shape the old query // rejected outright, because it tested the sign against '+' alone. ci(t, ix, "b1", "star-on-tip", "2026-01-02T10:00:00", "work") tag(t, ix, "b1", "closed", "*", "2026-01-02T10:00:00") // A propagating close INHERITED: the tag is on the parent, and the // tip that follows carries no tag of its own. ci(t, ix, "c1", "star-inherited", "2026-01-03T10:00:00", "work") tag(t, ix, "c1", "closed", "*", "2026-01-03T10:00:00") ci(t, ix, "c2", "star-inherited", "2026-01-03T10:00:01", "after the close", "c1") // Re-landed: closed with a NON-propagating tag, then committed to // again. The newer tip is not closed, so neither is the branch — // this is the case a branch-wide "latest closed tag wins" rule gets // wrong, and it is why the tip's own tag is read separately. ci(t, ix, "d1", "relanded", "2026-01-04T10:00:00", "work") tag(t, ix, "d1", "closed", "+", "2026-01-04T10:00:00") ci(t, ix, "d2", "relanded", "2026-01-04T11:00:00", "picked back up", "d1") // Cancelled: a propagating close undone by a later '-'. ci(t, ix, "e1", "reopened", "2026-01-05T10:00:00", "work") tag(t, ix, "e1", "closed", "*", "2026-01-05T10:00:00") ci(t, ix, "e2", "reopened", "2026-01-05T11:00:00", "reopen", "e1") tag(t, ix, "e2", "closed", "-", "2026-01-05T11:00:00") // Never closed at all. ci(t, ix, "f1", "live", "2026-01-06T10:00:00", "work") got := closedSet(t, ix) for branch, want := range map[string]bool{ "plain-plus": true, "star-on-tip": true, "star-inherited": true, "relanded": false, "reopened": false, "live": false, } { if got[branch] != want { t.Errorf("%s: closed = %v, want %v", branch, got[branch], want) } } }