git sync's 'deckle: save before sync' commit shows as an undo of page 'before sync' #270
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#270
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
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?
Found while verifying docs/api.md for #264.
gitreposync (internal/gitrepo/sync.go:55) commits pending work with the subjectdeckle: save before sync.parseSnapshotSubject(internal/server/git.go) reads deckle subjects as<op> [lang] <pages>, so after a sync that committed pending work,GET /api/git/statereportsundoOp: "save",undoPage: "before sync",undoPages: ["before sync"]— a page that does not exist.Expected: that commit is either not undoable as a page step, or its subject names the pages it carries (or is excluded by
parseSnapshotSubject), soundoPagenever names a non-page.Agent Brief
Summary:
The catch-up commit that sync and a branch-mode publish make of uncommitted working-tree changes (subjects
deckle: save before syncanddeckle: save before publish) is misread by the undo state as a page step on a page called "before sync". It must read as a commit that is not an editor step, so undo on any page stays offered and the Undo tooltip never names a non-page.Current behavior:
In branch mode,
Repo.Sync(internal/gitrepo/sync.go) andRepo.publishBranch(internal/gitrepo/publish.go) commit pending working-tree changes throughcommitWorktreewith the subjects above before doing their work. When that commit ends up as the draft tip,GET /api/git/statereportsundoOp: "save",undoPage: "before sync",undoPages: ["before sync"]andundoLang: <default>. The editor's reach check (undoReachinweb/src/undoinfo.ts) finds no open page matching that path, so the Undo button is disabled on every page with a tooltip naming the non-page ("Undo: save on before sync, just now").Reproduced at the parser:
parseSnapshotSubject("deckle: save before sync")returns opsave, pages["before sync"], oktrue;deckle: save before publishreturns opsave, pages["before publish"]. Thedeckle: saveanddeckle: wip snapshotdefaults are never reached because the server always passes a message;deckle: baselineanddeckle: publishparse with no pages and never sit at an undoable tip.Desired behavior:
For a draft tip whose subject is one of the git layer's catch-up subjects,
GET /api/git/statereportsundoAvailable: trueandundoTimeand omitsundoOp,undoPage,undoPagesandundoLang— exactly as it does today for a commit deckle did not write.POST /api/page/undoon a page that commit changed restores that page from the parent, as it does for any other step; on a page the commit did not touch the restore is a no-op. Every other subject keeps its current reading.Decisions:
de.jsonorundo_ops.jsonchange.WIPBaselineMessagealready is, and makecommitWorktree's callers use them. The server's subject parser calls that; the server must not string-match these subjects with its own literal, and the parser must not grow a second copy of the op vocabulary.Key interfaces:
commitWorktreeininternal/gitrepo(sync.go,publish.go) — become exported constants or an exported predicate on the subject.parseSnapshotSubjectininternal/server/git.go— returns okfalsefor those subjects, soundoState,undoPageSetandstepTranslationFilesall treat the step as an undescribed commit without further changes.docs/api.md,GET /api/git/state: theundo*bullet saysundoOpis absent "for a commit deckle did not write"; it gains the catch-up commit.POST /api/git/syncalready names the subject and may link to that bullet.cutSnapshotOplive ininternal/server/snapshot_ops.go; the client's absent-op handling isundoReach/undoStepTextinweb/src/undoinfo.tsand needs no change.Acceptance criteria:
parseSnapshotSubjectreturns okfalsefor both catch-up subjects and is unchanged for every subject built fromsnapshotOps(existing parser tests keep passing).POST /api/git/sync;GET /api/git/statehasundoAvailable: trueandundoTime, and none ofundoOp,undoPage,undoPages,undoLang.POST /api/page/undoon that page restores the pre-edit content and answers with the page's state.save before publishcommit as the draft tip (see assumptions).internal/gitrepo;internal/serverholds no literal of either.docs/api.mdstates the exclusion in theGET /api/git/stateundo*bullet.How to verify:
go test ./...,go vet ./...; the new branch-mode test fails before the fix (it seesundoPage: "before sync") and passes after.cd web && npm test— the client is unchanged; its "unknown" branch already covers absent keys.docs/docs_test.go, the route test ininternal/server) pass.Assumptions to check:
save before publishcommit can remain the draft tip after a path-scoped branch-mode publish (the draft is rebased onto the new main and collapses only when its tree equals main's). If it always collapses, that criterion reduces to the parser unit test.gitrepocaller commits with a free-formdeckle:subject that could collide with a vocabulary op — grepcommitWorktree,SnapshotWIP,CommitDraft,moveDraft(its reflog message is not a commit subject).Out of scope:
undo_ops.jsonchanges.deckle: saveanddeckle: wip snapshotdefaults, which the server never sends.