Check that the os-doc-hygiene reset --hard rollback cannot lose user work #1609

Closed
opened 2026-11-06 16:54:19 +00:00 by jared · 3 comments
Owner

Problem

plugins/os-doc-hygiene/skills/clean/SKILL.md (lines 443, 603-604, 697-698) rolls back with git reset --hard $BASELINE after a WIP checkpoint commit. If a path exists where the user's uncommitted work was not in the checkpoint, the work stays only in the reflog. cc-plugins/client-management/skills/migrate-client/workflows/migrate-project.md rolls back the same way with a tag. This is row G-114 and open item Q-2 in docs/os-git/call-site-checklist.md. It does not depend on os-git.

Reproduce

n/a: investigation. Build a scratch repository with uncommitted work, run the checkpoint and rollback steps as the skill text says, and see which user changes survive.

Approach

Trace each rollback path in the skill text. List every state in which reset --hard discards a change that no commit holds. Then give one of two results: the skill text needs a guard (for example, a clean-tree check before the checkpoint, or a restore of only the touched paths), or the paths are safe, with the evidence. Design Q2 recommends not offering reset --hard in v1 of os-git and restoring only touched paths (restore --source=<checkpoint> -- <paths>) when the plugin is ported. This ticket decides what to do with the current skill text.

Required work: none beyond the acceptance criteria.

Acceptance criteria

  1. Given a repository with uncommitted user changes in tracked and untracked files, when the skill runs its checkpoint and rolls back, then the ticket states which of those changes survive.
  2. Given an unsafe path, when the ticket closes, then the skill text has a guard that keeps the user's work, and a scratch-repository run shows it.
  3. Given all paths are safe, when the ticket closes, then a comment on this ticket records the evidence.
  4. Given the same check for the migrate-project.md tag rollback, when the ticket closes, then it records the result for that file as well.
  5. Given row G-114, when the ticket closes, then it is marked - [x] with the outcome in docs/os-git/call-site-checklist.md.

Non-goals

Moving the rollback into os-git. A Checkpoint object is deferred (design section 3.2).

Origin

  • Trigger: User request in session 1a5b2630-09c9-46cb-aee4-a5a98e2e7d24 on 2026-11-06: one os-git gem for all local git work in cc-os and the user's projects.
  • Improvised this session: none
  • Chain: possible loss of user work ← reset --hard after a WIP checkpoint ← DESIGN (plugins/os-doc-hygiene/skills/clean/SKILL.md)
  • Root candidate: none found; searched open issues for git, worktree, octokit, ruby port, python, statusline, reset --hard. Related but not a match: #845, #853, #857, #1527, #1554.
  • Where: plugins/os-doc-hygiene/skills/clean/SKILL.md
  • Session: 1a5b2630-09c9-46cb-aee4-a5a98e2e7d24
  • Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/1a5b2630-09c9-46cb-aee4-a5a98e2e7d24.jsonl
## Problem `plugins/os-doc-hygiene/skills/clean/SKILL.md` (lines 443, 603-604, 697-698) rolls back with `git reset --hard $BASELINE` after a WIP checkpoint commit. If a path exists where the user's uncommitted work was not in the checkpoint, the work stays only in the reflog. `cc-plugins/client-management/skills/migrate-client/workflows/migrate-project.md` rolls back the same way with a tag. This is row G-114 and open item Q-2 in `docs/os-git/call-site-checklist.md`. It does not depend on `os-git`. ## Reproduce n/a: investigation. Build a scratch repository with uncommitted work, run the checkpoint and rollback steps as the skill text says, and see which user changes survive. ## Approach Trace each rollback path in the skill text. List every state in which `reset --hard` discards a change that no commit holds. Then give one of two results: the skill text needs a guard (for example, a clean-tree check before the checkpoint, or a restore of only the touched paths), or the paths are safe, with the evidence. Design Q2 recommends not offering `reset --hard` in v1 of `os-git` and restoring only touched paths (`restore --source=<checkpoint> -- <paths>`) when the plugin is ported. This ticket decides what to do with the current skill text. Required work: none beyond the acceptance criteria. ## Acceptance criteria 1. Given a repository with uncommitted user changes in tracked and untracked files, when the skill runs its checkpoint and rolls back, then the ticket states which of those changes survive. 2. Given an unsafe path, when the ticket closes, then the skill text has a guard that keeps the user's work, and a scratch-repository run shows it. 3. Given all paths are safe, when the ticket closes, then a comment on this ticket records the evidence. 4. Given the same check for the `migrate-project.md` tag rollback, when the ticket closes, then it records the result for that file as well. 5. Given row G-114, when the ticket closes, then it is marked `- [x]` with the outcome in `docs/os-git/call-site-checklist.md`. ## Non-goals Moving the rollback into `os-git`. A `Checkpoint` object is deferred (design section 3.2). ## Origin - Trigger: User request in session 1a5b2630-09c9-46cb-aee4-a5a98e2e7d24 on 2026-11-06: one os-git gem for all local git work in cc-os and the user's projects. - Improvised this session: none - Chain: possible loss of user work ← reset --hard after a WIP checkpoint ← DESIGN (plugins/os-doc-hygiene/skills/clean/SKILL.md) - Root candidate: none found; searched open issues for git, worktree, octokit, ruby port, python, statusline, reset --hard. Related but not a match: #845, #853, #857, #1527, #1554. - Where: plugins/os-doc-hygiene/skills/clean/SKILL.md - Session: 1a5b2630-09c9-46cb-aee4-a5a98e2e7d24 - Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/1a5b2630-09c9-46cb-aee4-a5a98e2e7d24.jsonl
Author
Owner

Work started by the #1610 orchestrator, session 5b14a4ef-91b2-45c0-a729-baa17682a39a. Branch: ticket-1609.

Work started by the #1610 orchestrator, session 5b14a4ef-91b2-45c0-a729-baa17682a39a. Branch: ticket-1609.
Author
Owner

Findings for #1609 (commit 5807c183 on branch ticket-1609). Scratch repos: /tmp/claude-1000/-home-jared-dev-cc-os/5b14a4ef-91b2-45c0-a729-baa17682a39a/scratchpad/rollback-1609

clean/SKILL.md, old text: UNSAFE on a dirty tree. Checkpoint = add -A + commit, then BASELINE=HEAD~1, then reset --hard $BASELINE.

User change After old rollback
tracked edit lost from working tree (reflog only)
staged change lost (reflog only)
untracked file lost (it was committed in the checkpoint, then removed; reflog only)
ignored file survives (never touched)
mid-run tracked edit lost, nowhere
mid-run untracked file survives

Clean-tree path (BASELINE=HEAD): mid-run tracked edits are lost, nowhere; mid-run untracked and ignored files survive.

Fix (SKILL.md): BASELINE is the checkpoint commit. Added touched.paths and rollback_to_baseline (restore --source=BASELINE for touched paths; remove paths created by the skill). All four reset --hard sites now call it. add -A stays in the checkpoint (Q1 rider not part of this guard).
Replay of the new text: tracked, staged, untracked, ignored, and mid-run edits to untouched files all survive; touched docs revert; the created archive file is removed. Limit: a user edit made mid-run to a path the skill also touched is overwritten.

cc-plugins migrate-project.md (not edited): Phase 0 says STOP on a dirty tree (an instruction only; no check). git tag at HEAD, then reset --hard tag. Replay: clean start loses the migration commit (reflog), mid-run tracked edits (nowhere), and staged new files; unstaged untracked and ignored files survive. A dirty start loses tracked edits to the tag state. Unsafe in the same class.

Follow-ups: file a cc-plugins ticket for migrate-project.md; add a test for the rollback function.

Findings for #1609 (commit 5807c183 on branch ticket-1609). Scratch repos: /tmp/claude-1000/-home-jared-dev-cc-os/5b14a4ef-91b2-45c0-a729-baa17682a39a/scratchpad/rollback-1609 **clean/SKILL.md, old text: UNSAFE on a dirty tree.** Checkpoint = `add -A` + commit, then `BASELINE=HEAD~1`, then `reset --hard $BASELINE`. | User change | After old rollback | |---|---| | tracked edit | lost from working tree (reflog only) | | staged change | lost (reflog only) | | untracked file | lost (it was committed in the checkpoint, then removed; reflog only) | | ignored file | survives (never touched) | | mid-run tracked edit | lost, nowhere | | mid-run untracked file | survives | Clean-tree path (BASELINE=HEAD): mid-run tracked edits are lost, nowhere; mid-run untracked and ignored files survive. **Fix (SKILL.md):** BASELINE is the checkpoint commit. Added `touched.paths` and `rollback_to_baseline` (restore --source=BASELINE for touched paths; remove paths created by the skill). All four `reset --hard` sites now call it. `add -A` stays in the checkpoint (Q1 rider not part of this guard). **Replay of the new text:** tracked, staged, untracked, ignored, and mid-run edits to untouched files all survive; touched docs revert; the created archive file is removed. Limit: a user edit made mid-run to a path the skill also touched is overwritten. **cc-plugins migrate-project.md (not edited):** Phase 0 says STOP on a dirty tree (an instruction only; no check). `git tag` at HEAD, then `reset --hard tag`. Replay: clean start loses the migration commit (reflog), mid-run tracked edits (nowhere), and staged new files; unstaged untracked and ignored files survive. A dirty start loses tracked edits to the tag state. Unsafe in the same class. Follow-ups: file a cc-plugins ticket for migrate-project.md; add a test for the rollback function.
Author
Owner

Resolution

Done: Traced the clean/SKILL.md rollback and the migrate-project.md tag rollback by replay. clean/SKILL.md was unsafe; it now restores only touched paths from the checkpoint. G-114 and Q-2 marked.

Evidence: 5807c183. Scratch replay of the new text: tracked, staged, untracked, ignored, and mid-run edits to untouched files survive; touched docs revert; created archive removed. Findings comment on this ticket. Known limit: a mid-run user edit to a path the skill also touched is overwritten.

Follow-ups: migrate-project.md finding sent to #1600 (row G-120). Rollback-function test dropped: the bash lives in SKILL.md text, and Q2 moves rollback into Ruby at the os-doc-hygiene port.

## Resolution **Done:** Traced the clean/SKILL.md rollback and the migrate-project.md tag rollback by replay. clean/SKILL.md was unsafe; it now restores only touched paths from the checkpoint. G-114 and Q-2 marked. **Evidence:** 5807c183. Scratch replay of the new text: tracked, staged, untracked, ignored, and mid-run edits to untouched files survive; touched docs revert; created archive removed. Findings comment on this ticket. Known limit: a mid-run user edit to a path the skill also touched is overwritten. **Follow-ups:** migrate-project.md finding sent to #1600 (row G-120). Rollback-function test dropped: the bash lives in SKILL.md text, and Q2 moves rollback into Ruby at the os-doc-hygiene port.
jared closed this issue 2026-11-06 17:16:30 +00:00
Sign in to join this conversation.
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
jared/cc-os#1609
No description provided.