Initial publish v0.1.0: standalone workflow core (corpus + examples + guards)
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
## 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].
|
||||
Reference in New Issue
Block a user