Skip to content

feat: osa stop --wipe-data to clear all local state - #15

Merged
rorybyrne merged 4 commits into
mainfrom
feat/stop-wipe-data
Jul 27, 2026
Merged

feat: osa stop --wipe-data to clear all local state#15
rorybyrne merged 4 commits into
mainfrom
feat/stop-wipe-data

Conversation

@rorybyrne

Copy link
Copy Markdown
Contributor

Adds a --wipe-data flag to osa stop for a clean local reset.

  • Default (osa stop) runs docker compose down, keeping the named Postgres volume so the DB survives stop/start (unchanged behaviour).
  • osa stop --wipe-data additionally passes --volumes (drops the Postgres volume) and removes the ./.data host bind mount — deposited files and hook artifacts that down --volumes doesn't touch — so all local state is cleared.

Safety:

  • A failed down raises before any deletion, so a broken stop never destroys data.
  • A missing .data dir is tolerated (no error).
  • Removal errors surface a clear hint (container-owned files may need manual removal).

Tests cover: default keeps volume + data, --wipe-data drops both, missing .data tolerated, and a failed stop preserves data.

By default `osa stop` runs `docker compose down`, keeping the named Postgres
volume so the DB survives stop/start. `--wipe-data` additionally passes
`--volumes` (drops the DB volume) and removes the `./.data` host bind mount
(deposited files + hook artifacts), so local state is fully cleared.

A failed `down` aborts before any deletion, and a missing `.data` dir is
tolerated, so the flag never destroys data on an unsuccessful stop.
@greptile-apps

greptile-apps Bot commented Jul 27, 2026

Copy link
Copy Markdown

Greptile Summary

Adds an optional destructive reset path to osa stop.

  • Preserves existing stop behavior unless --wipe-data is supplied.
  • Stops containers, removes the .data bind-mounted state, and then removes Compose volumes.
  • Adds handling and regression coverage for stop failures, missing data directories, filesystem-removal failures, and volume-removal failures.
  • Updates the locked project version to 0.7.0.

Confidence Score: 5/5

The PR appears safe to merge because no new blocking failure eligible for this follow-up review remains.

No blocking failure remains beyond the behavior already covered by the existing review threads.

T-Rex T-Rex Logs

What T-Rex did

  • Before CLI baseline, T-Rex inspected the CLI stop help baseline log to confirm the option is absent.
  • Before test baseline, T-Rex reviewed the CLI instance lifecycle before log and confirmed exit code 0 with 70 tests passed.
  • After CLI help, T-Rex checked the CLI stop help after log and confirmed exit code 0 with the destructive option shown.
  • After test run, T-Rex verified the CLI instance lifecycle after log and confirmed exit code 0 with 76 tests passed.

View all artifacts

T-Rex Ran code and verified through T-Rex

Important Files Changed

Filename Overview
osa/cli/instance.py Adds the wipe orchestration, ordered failure handling, and user-facing recovery guidance.
osa/cli/main.py Exposes --wipe-data on the stop command and forwards it to the instance layer.
tests/test_instance.py Covers preservation defaults, successful wipes, missing directories, and failure ordering.
uv.lock Updates only the editable osa-py package version from 0.6.0 to 0.7.0.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[osa stop] --> B{--wipe-data?}
B -- No --> C[docker compose down]
B -- Yes --> D[docker compose down]
D --> E{Stop succeeded?}
E -- No --> F[Exit without deleting local state]
E -- Yes --> G[Remove .data]
G --> H{Removal succeeded or directory absent?}
H -- No --> I[Exit with database volume intact]
H -- Yes --> J[docker compose down --volumes]
J --> K{Volume removal succeeded?}
K -- Yes --> L[Local state wiped]
K -- No --> M[Exit and advise retry]
Loading

Reviews (4): Last reviewed commit: "docs: document the wipe ordering trade-o..." | Re-trigger Greptile

Comment thread osa/cli/instance.py Outdated
Comment on lines +437 to +438
# `down` alone keeps named volumes (the DB persists across stop/start).
# `--volumes` additionally removes them — here, the postgres_data DB volume.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Wipe leaves partially deleted state

When .data contains container-owned files that the host user cannot remove, down --volumes permanently deletes the Postgres database before shutil.rmtree raises, causing the command to fail with deposited files and hook artifacts left orphaned on disk.

Artifacts

Repro: focused pytest harness exercising the real stop_instance path

  • Evidence file captured while the check ran.

Repro: verbose execution log showing down --volumes precedes the failed host removal and retained data

  • The full command output behind this check.

View artifacts

T-Rex Ran code and verified through T-Rex

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in f0a54bc. Reordered so --wipe-data destroys nothing until it can destroy everything: stop containers keeping volumes → remove ./.data → only then down --volumes. If .data removal fails (container-owned files), we abort with the DB volume intact rather than half-wiping, and the error says so + hints to remove with elevated permissions and retry. Added a regression test asserting the volume drop never runs when data removal fails.

Previously `down --volumes` dropped the DB volume before removing ./.data, so
if the bind-mount held container-owned files the host couldn't delete, the DB
was already gone when shutil.rmtree raised — leaving deposited files orphaned
and the command failed (Greptile P1).

Reorder so nothing is destroyed until everything can be: stop containers keeping
volumes, remove ./.data (abort here with the DB intact on failure), then drop
the volumes. Adds a regression test asserting the volume drop never runs when
data removal fails.
Comment thread osa/cli/instance.py
"container-owned), then re-run `osa stop --wipe-data`.",
) from e

wiped = run_streamed([*cmd, "down", "--volumes"], task=task, cwd=project_dir)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Volume failure leaves partial wipe

When .data removal succeeds but the subsequent docker compose down --volumes command fails, the deposited files and hook artifacts are already irreversibly deleted while the Postgres volume remains, causing the command to exit with a partially wiped instance.

Artifacts

Repro: focused pytest harness executing the partial-wipe failure path

  • Evidence file captured while the check ran.

Repro: verbose pytest output showing deleted files, failed volume removal, and InstanceError

  • The full command output behind this check.

View artifacts

T-Rex Ran code and verified through T-Rex

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one is inherent: a host bind mount (./.data) and a Docker volume can't be deleted atomically, so some single-step failure can always leave a partial state. What we can control is which failure and how recoverable it is:

  • The common failure is .data removal (container-owned files on Linux). That step runs first, so its failure aborts before anything is destroyed — DB volume intact.
  • The volume drop runs last and rarely fails (containers are already down; it's essentially docker volume rm). If it does, the state is files gone, volume remaining — and re-running osa stop --wipe-data completes it idempotently (the missing .data is tolerated). The error message directs exactly that.

Documented the trade-off in a comment and added test_wipe_volume_drop_failure_is_recoverable proving the re-run finishes the wipe (96595e2). I don't think it's worth trading this rare, recoverable case for the common-and-unrecoverable one the other ordering produces.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a well-reasoned argument, and the added comment + test make the trade-off explicit and verifiable. The "common failure is safe, rare failure is recoverable" ordering is the right call here — the original concern is addressed.

Tip: You can customize Greptile's behavior for this repo with .greptile/rules.md and .greptile/config.json.

Follow-up to the reorder (Greptile): deleting a host bind mount and a Docker
volume can't be atomic. We order the likely-to-fail step (./.data removal)
first, so the common failure aborts before any destruction; the volume drop
rarely fails and, if it does, the wipe is merely incomplete and re-running
finishes it idempotently. Documents this in a comment and adds a test proving
the volume-drop failure is recoverable by re-running.
@rorybyrne
rorybyrne merged commit 0c0672a into main Jul 27, 2026
4 checks passed
@rorybyrne
rorybyrne deleted the feat/stop-wipe-data branch July 27, 2026 13:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant