perf(history): parse each blob once and grep main's tip once per request #309
No reviewers
Labels
No labels
bug
enhancement
needs-triage
ready-for-agent
ready-for-human
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Cloonar/deckle!309
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "afk/289"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #289
What
Two internal speed-ups to
GET /api/element/history, with no wire change.perf(gitrepo): …)FileBlobgainsID, the blob's git object id.readBlobskeeps it from thecat-file --batchheader it already parsed, so there is no extra git call.blobsAt,holdingNeedle,historyEdits,NeedleFilesandDraftEdits.NeedleHistoryreturns a fourth value,start: the kept files holding the needle at the window's start. It is built from theholdingFileslookup and the batch the function already runs, and equalsNeedleFiles(S, …)by construction. A test pins that equality on every page, for windows 0–5 and threeKeepfilters.perf(history): …)locateElementis now a method on a request-scopedelementLocator. It caches each blob's located answer byFileBlob.ID, so a distinct blob is parsed at most once per request.editAuthors(mergeEditsand draft edits),pendingAuthors(the draft tip) andhistoryWorkingTree. Working-tree files have no id and are parsed uncached.DiffElement,ElementTitle,identify, JSON) mutates them.start, so it runs onegit grepat the tip and onecat-file --batch. Continuation pages still callNeedleFiles(tip, …).grepHolding/holdingFilesis still the only "files holding the needle at a commit" lookup.elementLocator.locateElementis still the only parse-and-locate. No "same as" comments.Evidence
diff -ris empty. It covers:TestElementHistoryParsesEachBlobOnce: each blob id is parsed exactly once per request, and the cache must be hit at least once. Runs over version pages, a merge'sEdits,DraftEditsand the draft tip.TestElementHistoryGrepsTipOnce(counts viaGIT_TRACE): a first page runs 1 grep at the tip and 1 batch. A continuation page runs a grep at the tip and one at the window start.TestFileBlobIDs,TestFileBlobIDsOfEditsandTestNeedleHistoryStartIsNeedleFilesin gitrepo.NeedleHistorycall sites only gain a_.go build ./...,go vet ./...,gofmt -landgo test ./...are all clean.Before/after, same machine
Alternating runs of base, new, base, new (go 1.26.8, git 2.47.3):
TestElementHistoryCostBoundmedianBenchmarkElementHistory(10x)NeedleFileson the request pathNeedleHistory, 200 versionsThat is about 45 ms (roughly 23%) off a default-window request, slightly more than the 30–40 ms PR #287 estimated.
Docs and skills
No changes. ADR 0023 quotes only the pickaxe time (about 60 ms) and "well under a quarter of a second", and both are still true.
docs/architecture.md,docs/api.md,scaffold/site/AGENTS.mdand the scaffolded skills document nothing this change moves.🤖 Generated with Claude Code
[autoland] verdict: pass
PASS — signal: labctl pr checks 309 = success (ci / build-and-test green; release skipped). Title is Conventional Commits, body carries Closes #289, diff stays within the issue (internal/gitrepo + internal/server history only, no wire change). Rule owners kept: elementLocator.locateElement is the sole parse-and-locate; holdingFiles/grepHolding the sole holding-files grep; NeedleHistory's start = blobsAt(blobs, at, holdingFiles(at)), the same path NeedleFiles takes, pinned by TestNeedleHistoryStartIsNeedleFiles. Shared located shortcodes are only read (DiffElement/sourceText build new nodes). Existing tests changed only at NeedleHistory call sites. gofmt -l clean. Docs/skills untouched, correctly: no documented behaviour moves.