114 lines
4.8 KiB
Markdown
114 lines
4.8 KiB
Markdown
## Stash Discipline (mandatory)
|
|
|
|
> Enforcement layer: **L0 tool-enforced** (bash guard + husky hooks) — this
|
|
> file is reference/documentation, NOT part of any `agents_md` per-turn
|
|
> injection whitelist since the 2026-08-27 injection-budget batch-1. Do not
|
|
> re-add it to a whitelist; the guard enforces regardless.
|
|
|
|
In the octopus worktree model, multiple parallel sessions share a single git
|
|
repository. The git **stash stack is repository-global** (`stash@{0}`,
|
|
`stash@{1}`, …) and is NOT isolated per worktree. When two sessions in
|
|
different worktrees run `git stash` / `git stash pop`, they silently index
|
|
each other's entries and one session's `pop` returns the other session's
|
|
content — or `drop`/`clear` wipes uncommitted work belonging to a session in
|
|
a different worktree.
|
|
|
|
This failure mode has already destroyed completed work in production ([org-internal #1655] /
|
|
[org-internal #1629] — a finished 25-test implementation overwritten on the shared stack).
|
|
|
|
**Iron Law: NEVER use `git stash` (or `git stash pop` / `push` / `drop` /
|
|
`clear` / `apply`) inside an octopus worktree.**
|
|
|
|
The bash tool enforces this at L0 via a safety-floor pattern that blocks
|
|
`git stash` invocations. Use one of the following instead — they are
|
|
worktree-local and cannot be clobbered by a parallel session:
|
|
|
|
### Approved alternatives
|
|
|
|
1. **WIP commit on the current workflow branch** (preferred for
|
|
mid-iteration checkpoints):
|
|
|
|
```bash
|
|
git add -A
|
|
git commit -m "wip: <slug> — <one-line state>"
|
|
# … later, before the real commit:
|
|
git reset --soft HEAD~1 # un-commit but keep the work staged
|
|
```
|
|
|
|
The per-iteration commit model already expects these to be cleaned up by
|
|
amend / interactive rebase before merge, so a `wip:` commit is never a
|
|
long-term smell.
|
|
|
|
2. **Throwaway side branch** (preferred when you must switch branches and
|
|
cannot commit yet):
|
|
|
|
```bash
|
|
git switch -c wip/<slug>-<topic>
|
|
git add -A && git commit -m "wip: <slug> — <one-line state>"
|
|
git switch - # back to the workflow branch
|
|
# … later:
|
|
git cherry-pick wip/<slug>-<topic> # or merge / reset as needed
|
|
git branch -D wip/<slug>-<topic>
|
|
```
|
|
|
|
3. **`git diff > /tmp/octopus/<slug>.patch`** (last resort, when even a WIP
|
|
commit is impossible — e.g. the index is in a conflicted state you do not
|
|
want to disturb):
|
|
|
|
```bash
|
|
git diff --binary > /tmp/octopus/<slug>.patch
|
|
git apply /tmp/octopus/<slug>.patch # restore later
|
|
```
|
|
|
|
Keep the patch under `/tmp/octopus/` so it survives the session but is
|
|
never accidentally committed (see wiki page `rules/temp-files`, L2
|
|
on-demand).
|
|
|
|
### What about switching away from a dirty tree?
|
|
|
|
If you must `git checkout <base>` to reproduce a failure but the worktree is
|
|
dirty, do **not** reach for stash. Instead:
|
|
|
|
- WIP-commit first (option 1), or
|
|
- Use the lifecycle-managed scratch-worktree script ([org-internal #2790]) to materialise
|
|
the base commit in a *separate* worktree and run the failing test there:
|
|
|
|
```bash
|
|
bash script/scratch-worktree.sh create <slug>-base <base>
|
|
bash script/scratch-worktree.sh remove <slug>-base
|
|
```
|
|
|
|
This is the pattern the `verify` skill uses for the regression-vs-baseline
|
|
classification check. The script registers the worktree, symlinks
|
|
`node_modules` from the source checkout when `bun.lock` matches, and the
|
|
`sweep` backstop reclaims worktrees abandoned by dying sessions — bare
|
|
`git worktree add /tmp/octopus/...` has no such recovery ([org-internal #2790]).
|
|
|
|
### Exceptions
|
|
|
|
- Running `git stash list` / `git stash show` to *inspect* the stack (no
|
|
mutation) is allowed — it cannot lose work. The safety-floor pattern only
|
|
blocks mutating subcommands (`push`, `pop`, `apply`, `drop`, `clear`,
|
|
`create`, `store`, `branch`, and bare `git stash`).
|
|
- The TUI's **prompt stash** (`prompt.stash` keybind, `usePromptStash`) is
|
|
unrelated — it stashes *input text* in memory, not git refs, and is not
|
|
affected by this rule.
|
|
|
|
### Enforcement
|
|
|
|
- **L0 (tool-enforced)**: `packages/octopus/src/tool/bash.ts` adds
|
|
`/\bgit\s+stash\b(?:\s+(?:push|pop|apply|drop|clear|create|store|branch)|\s*$)/`
|
|
to `SAFETY_FLOOR_PATTERNS`. Safety-floor items cannot be unblocked via
|
|
configuration; bypass requires `--no-security-config`.
|
|
- **L1 (this file)**: reference documentation only — removed from every
|
|
`agents_md` injection whitelist (2026-08-27, see header); the L0 guard
|
|
enforces regardless.
|
|
- **L2 (skills)**: any skill that suggests `git stash` is a defect — file it
|
|
under Kind/Enhancement with the `retrospective` label (`verify` SKILL.md
|
|
already uses `script/scratch-worktree.sh` instead).
|
|
|
|
If a parallel-session stash collision happens again despite this rule, treat
|
|
it as a Sev-2 process incident: stop work, recover via
|
|
`git fsck --unreachable` / `git log -g --walk-reflogs stash`, open a follow-up
|
|
referencing [org-internal #1655].
|