feat(history): GET /api/element/history — an element's publish history derived from main #287
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!287
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "afk/283"
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 #283
What
GET /api/element/history?uid=&lang=&before=returns the publish history of one content element in one language's file. Every publish tomainthat changed the element's own content is listed newest first, ascreated,changedorremoved, each with a labelled field-level diff. Apendingtop row shows the working tree againstmain. The history is derived from git on demand, and nothing is written at save or publish time (ADR 0023). The route is documented indocs/api.md.How
internal/elemops/compare.gois now the only place that compares two versions of an element.internal/server/pending.go. The panel's counts are unchanged, and every handler-level pending test passes untouched.DiffElementadds the field diff:enabled, viaelement.EnabledFieldsourcefallback, so an entry is never emptyinternal/worddiff.internal/gitrepo/history.goreads the git side:MainTipresolvesmainonce per request.NeedleHistoryrunsgit grepand the pickaxe (-S'uid="…"', renames off) over a 1,000-commit range window with a cursor, then onecat-file --batch. Whether a file holds the element is decided from the file's content.NeedleFileslists the files that hold the uid at one commit.internal/server/history.gois the handler:changedentry.mainit answers like the pending panel:200withunavailableand its code.history.badCursor,history.unknownElement,history.read,label.body,label.source.servermessages.json,en.jsonandde.jsonare updated.elemops.ElementLabelis now the one rule for "sidecar label, else the element name". It was previously written inline twice inlinktargets.go, and the history needed it too.Verification
go vet ./...andgo test ./...pass.cd web && npm testpasses: 124 files, 3213 tests.DECKLE_HISTORY_PERF=1 go test ./internal/server -run TestElementHistoryCostBound -v): on a generated repository of 300 pages × 15 elements and 2,000 publishes touching 3 pages each, one default-window request has a median of about 190 ms, against the 250 ms bound. The wall-clock check sits behind an env var so it can't flake in shared CI;BenchmarkElementHistorymeasures the same request.TestPickaxeListsOnlyCountChangedFilescovers it.Notes
scaffold/site/AGENTS.md, the theme README or any skill, because no sidecar, grammar or procedure changes.Issue #283.and should become the commit/PR reference once merged, as earlier ADRs do.main's tip once instead of twice. Together they would save about 30–40 ms.🤖 Generated with Claude Code
[autoland] verdict: pass
PASS. Signal relied on: CI aggregate
success(ci / build-and-test: npm ci/build/test, go vet ./..., go test ./..., go build). Not re-run. gofmt -l on the changed Go files is clean.Conventions: the Conventional Commits title is fine,
Closes #283is present, and the branch is level with main (merge-base = origin/mainbf70703).Scope against #283: every acceptance criterion is implemented and tested.
Nits (not blocking): the ADR 0023 source line reads 'Issue #283.' The retro-written ADRs 0001–0022 carry commit and PR references, so a later docs sync can add them. The package comment's first paragraph in internal/gitrepo/doc.go has one over-long line after the edit.