fix(git): the catch-up commit of a sync or publish is not a page step #277

Merged
dominik.polakovics merged 1 commit from afk/270 into main 2026-10-13 22:39:23 +02:00

Closes #270

What

Sync and a branch-mode publish commit any uncommitted working-tree changes before they start, with the subjects deckle: save before sync and deckle: save before publish. parseSnapshotSubject read those as an op save on a page named before sync (or before publish). As a result, GET /api/git/state reported undoPage: "before sync", and the editor disabled Undo on every page.

  • One owner: internal/gitrepo now exports SyncCatchUpMessage, PublishCatchUpMessage and IsCatchUpMessage, and sync.go and publish.go use them. internal/server contains no literal of either subject.
  • Parser: parseSnapshotSubject returns ok false for a catch-up subject. The undo state therefore treats that tip as a commit deckle did not write: undoAvailable and undoTime are present, and undoOp, undoPage, undoPages and undoLang are absent. Undo restores the open page from the tip's parent. No client, catalog or undo_ops.json change.
  • Docs: in docs/api.md, the undo* bullet of GET /api/git/state now names the exclusion, and POST /api/git/sync links to it.

Tests

  • TestSnapshotSubjectCatchUpIsNoStep: both subjects parse as ok false.
  • TestBranchModeSyncCatchUpIsUnnamedUndo: hand-edit a page, sync, check that git/state carries no op or page, then undo the page and check the pre-edit content is back.
  • TestBranchModePublishCatchUpIsUnnamedUndo: the publish catch-up commit as the draft tip.
  • All three fail with the parser change disabled. They reported undoPage = before sync / before publish.

Note on the publish scenario. The server has no path-scoped publish: POST /api/publish-all → PublishAll, and PublishPaths has no non-test caller. A hand edit inside the publish roots is therefore always published, and the catch-up commit collapses. The commit stays as the draft tip only when the pending change includes a file outside those roots. The test uses a hand-edited layout for that. Undo on the published page answers with the page state and leaves the published content in place, because the commit's parent is the new main.

Verification

go vet ./..., go test ./..., gofmt -l, and cd web && npm test (3210 passed) are all green.

🤖 Generated with Claude Code

Closes #270 ## What Sync and a branch-mode publish commit any uncommitted working-tree changes before they start, with the subjects `deckle: save before sync` and `deckle: save before publish`. `parseSnapshotSubject` read those as an op `save` on a page named `before sync` (or `before publish`). As a result, `GET /api/git/state` reported `undoPage: "before sync"`, and the editor disabled Undo on every page. - **One owner:** `internal/gitrepo` now exports `SyncCatchUpMessage`, `PublishCatchUpMessage` and `IsCatchUpMessage`, and `sync.go` and `publish.go` use them. `internal/server` contains no literal of either subject. - **Parser:** `parseSnapshotSubject` returns ok `false` for a catch-up subject. The undo state therefore treats that tip as a commit deckle did not write: `undoAvailable` and `undoTime` are present, and `undoOp`, `undoPage`, `undoPages` and `undoLang` are absent. Undo restores the open page from the tip's parent. No client, catalog or `undo_ops.json` change. - **Docs:** in `docs/api.md`, the `undo*` bullet of `GET /api/git/state` now names the exclusion, and `POST /api/git/sync` links to it. ## Tests - `TestSnapshotSubjectCatchUpIsNoStep`: both subjects parse as ok `false`. - `TestBranchModeSyncCatchUpIsUnnamedUndo`: hand-edit a page, sync, check that git/state carries no op or page, then undo the page and check the pre-edit content is back. - `TestBranchModePublishCatchUpIsUnnamedUndo`: the publish catch-up commit as the draft tip. - All three fail with the parser change disabled. They reported `undoPage = before sync` / `before publish`. **Note on the publish scenario.** The server has no path-scoped publish: `POST /api/publish-all` → `PublishAll`, and `PublishPaths` has no non-test caller. A hand edit inside the publish roots is therefore always published, and the catch-up commit collapses. The commit stays as the draft tip only when the pending change includes a file outside those roots. The test uses a hand-edited layout for that. Undo on the published page answers with the page state and leaves the published content in place, because the commit's parent is the new main. ## Verification `go vet ./...`, `go test ./...`, `gofmt -l`, and `cd web && npm test` (3210 passed) are all green. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
fix(git): the catch-up commit of a sync or publish is not a page step
All checks were successful
ci / build-and-test (pull_request) Successful in 3m15s
ci / release (pull_request) Has been skipped
4c9bb16892
Sync and a branch-mode publish commit uncommitted working-tree changes as
"deckle: save before sync" / "deckle: save before publish". The undo state
read those as a save of a page named "before sync", disabling Undo on every
page with a tooltip naming a non-page.

The git layer now owns those subjects (SyncCatchUpMessage,
PublishCatchUpMessage, IsCatchUpMessage) and parseSnapshotSubject reads
them as a commit deckle did not write: git/state offers the undo with
undoTime only, and undo restores the open page from the tip's parent.

Closes #270

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Author
Owner

[autoland] verdict: pass

PASS — signal: ci / build-and-test (pull_request) green (aggregate success, run 279). Conventions: Conventional Commits title, Closes #270 present. Scope matches the #270 Agent Brief: the catch-up subjects are exported once in internal/gitrepo/snapshot.go:57-66 (SyncCatchUpMessage, PublishCatchUpMessage, IsCatchUpMessage) and used by sync.go:55 and publish.go:253. parseSnapshotSubject (internal/server/git.go:471) calls that predicate, so undoState, undoPageSet and stepTranslationFiles all treat the commit as undescribed. internal/server holds no literal of either subject. The docs/api.md undo* bullet and POST /api/git/sync are updated. No skill or AGENTS.md surface is affected. Locally verified that the three new tests fail with the guard disabled (undoPage = before sync / before publish) and pass with it.

[autoland] verdict: pass PASS — signal: ci / build-and-test (pull_request) green (aggregate success, run 279). Conventions: Conventional Commits title, Closes #270 present. Scope matches the #270 Agent Brief: the catch-up subjects are exported once in internal/gitrepo/snapshot.go:57-66 (SyncCatchUpMessage, PublishCatchUpMessage, IsCatchUpMessage) and used by sync.go:55 and publish.go:253. parseSnapshotSubject (internal/server/git.go:471) calls that predicate, so undoState, undoPageSet and stepTranslationFiles all treat the commit as undescribed. internal/server holds no literal of either subject. The docs/api.md undo* bullet and POST /api/git/sync are updated. No skill or AGENTS.md surface is affected. Locally verified that the three new tests fail with the guard disabled (undoPage = before sync / before publish) and pass with it.
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Cloonar/deckle!277
No description provided.