jj: document the restore, divergent, and squash traps
Each trap cost real work and reported success while doing it. `jj
restore FILE` reset a file to its parent to back out one sed and took
unrelated uncommitted work with it. `jj squash` with only `--into`
moved nothing because `@` had advanced past the commit holding the
changes, yet still printed "Rebased 3 descendant commits" and gave the
destination a new commit ID, so the no-op read as success. Concurrent
workspaces produce the same "my edits vanished" symptom by a third
route, so a new Divergent Changes section covers recovery — including
that `abcd/0` offsets are ordered by recency and shift under a
concurrent rewrite. jj-workspaces gains a red flag for rewriting a
revision another workspace has checked out and routes to that section
rather than repeating the recovery steps.

Also moves the "never authoritative, run --help" note to the top, where
it is read before the rest of the skill rather than after, and cuts a
paragraph that only restated the commit/describe/new table.

Assisted-by: Claude Opus 5 via Claude Code
change yvqosknktpmmkwrtrkzmzxkwszzzssoy
commit 49d8f0f7dbf29ca2d06252733e01218993ce6247
author Alpha Chen <alpha@kejadlen.dev>
date
parent lsxlynmv
diff --git a/ai/skills/jj-workspaces/SKILL.md b/ai/skills/jj-workspaces/SKILL.md
index e1ad1e2e..99fadbb0 100644
--- a/ai/skills/jj-workspaces/SKILL.md
+++ b/ai/skills/jj-workspaces/SKILL.md
@@ -124,6 +124,10 @@ Use Task tool to dispatch in parallel. **Start agents in the workspace directory
 - `jj workspace` commands
 - `jj git push`
 - `jj rebase`
+- Rewriting a commit another workspace has checked out (`describe`,
+  `squash`, `abandon`, `restore --into`). Check `jj log -r
+  'working_copies()'` before touching any revision other than `@`. Two
+  workspaces rewriting the same commit is what produces divergent changes.
 - Any work outside assigned workspace
 
 ### Phase 4: Review (Coordinator)
@@ -177,6 +181,7 @@ jj workspace update-stale
 | Empty WC commits after rebase | After rebase + forget, run `jj abandon 'empty() & description(exact:"") & @-'` to drop the workspace's leftover empty WC |
 | Forgetting cleanup | Remove directories after forgetting workspace |
 | jj not seeing file changes | Run `jj` or `jj status` periodically—jj only snapshots on command execution |
+| Files written in one workspace vanish | Concurrent rewrite left the change divergent. See the `jj` skill's Divergent Changes section—recover, don't rewrite |
 
 ## Red Flags
 
diff --git a/ai/skills/jj/SKILL.md b/ai/skills/jj/SKILL.md
index e8ff52ae..7bde60d8 100644
--- a/ai/skills/jj/SKILL.md
+++ b/ai/skills/jj/SKILL.md
@@ -5,7 +5,8 @@ description: Use when running any jj (Jujutsu) version control command — commi
 
 # Jujutsu (jj) Version Control
 
-Use `jj --help` for authoritative command reference and current flags.
+Never treat this skill as authoritative. Run `jj <command> --help` to verify
+behavior, flags, and current options.
 
 ## Core Workflow
 
@@ -25,10 +26,6 @@ they move `@`:
 | `jj new <rev>` | no | yes, to a new empty commit | start fresh work on top of `<rev>` |
 | `jj commit -m` | yes, on `@` | yes, to a new empty commit | finish `@` and move on — `describe @` + `new` in one step |
 
-So `jj commit` is just `jj describe` followed by `jj new`. Reach for
-`describe` when you only want to fix the current message without moving
-on; `new` when you want a fresh commit without touching messages.
-
 **Prefer `jj commit` over `jj squash`.** Create new commits by default —
 even for refactors, cleanups, or small follow-ups. Only squash when the
 prior commit specifically needs fixing up (e.g., correcting a bug it
@@ -93,6 +90,34 @@ jj restore SOME_FILE                       # restore file from parent
 jj restore --from kn --into kn FILE        # restore file in a specific revision
 ```
 
+**`jj restore FILE` is not "undo my last edit."** It resets the whole
+file to the parent revision, wiping *every* uncommitted change in it —
+not just the one you meant to back out. Backing out a temporary sed
+this way also destroyed unrelated in-progress work in the same file.
+Before restoring, run `jj diff FILE` to see everything that would be
+lost; to back out one surgical experiment, revert it with the same
+tool that made it (another sed/edit) instead of `jj restore`.
+
+## Divergent Changes
+
+A change is divergent when it has more than one visible commit — most often
+because two workspaces rewrote it concurrently. jj labels these
+`(divergent)` in the log, and the edits from one side appear to have
+vanished. Don't rewrite the missing files; recover them:
+
+```bash
+jj log -r 'divergent()'              # find them
+jj diff -r <commit> --name-only      # see what each holds
+jj restore --from <commit> <paths>   # recover
+```
+
+A bare change ID errors once it's divergent, so use the change offsets jj
+suggests (`abcd/0`, `abcd/1`) to inspect them. Offsets are assigned by
+recency, with the most recent commit at `/0`, so re-read `jj log` rather
+than reusing an offset from earlier in a session — a concurrent rewrite in
+another workspace shifts them all down by one. For `jj abandon`, pass the
+short commit ID, as jj's own hint recommends.
+
 ## Common Pitfalls
 
 **Avoid revset functions with parentheses.** Claude Code's shell
@@ -156,6 +181,18 @@ jj log --cwd /path/to/repo         # WRONG — no such flag; fails silently
 **Put `-m` before `--` or fileset args.** jj parses everything after `--` as
 fileset, so `-m` placed after `--` becomes a parse error.
 
+**`jj squash` takes its source from `@` unless you pass `--from`.** Naming
+only `--into <rev>` and a fileset moves that fileset out of `@`, not out of
+the commit you were reading about. When `@` has moved since you last ran
+`jj log` — the human committing in another terminal is enough — the squash
+moves nothing, yet still prints "Rebased N descendant commits" and gives the
+destination a new commit ID, so a no-op looks like it worked. Name the source
+and re-check `jj st` immediately before any rewrite:
+
+```bash
+jj squash --from <rev> --into <rev> -u FILE   # explicit source
+```
+
 **`jj squash` opens `$EDITOR` to merge descriptions and hangs in
 non-interactive shells.** When source and destination both have
 descriptions, jj launches the editor to combine them — Claude Code's
@@ -170,8 +207,3 @@ jj squash -m 'new message'            # inline replacement
 
 The same applies to `jj squash --from X --into Y`. If you actually want
 to merge the two descriptions, do it from a real terminal.
-
-## When to Use jj --help
-
-Never rely on this skill as authoritative. Always run `jj <command> --help`
-to verify behavior, flags, and current options.