TL;DR: A dry run must be side-effect free: no branches pushed, no PRs opened, no comments posted. Audit the dry-run code path for every external write and gate each one behind the flag. Until it is fixed, treat the agent's dry run as "no-merge mode" and run it against a throwaway fork if you need true isolation.

```text
agent's dry-run mode still pushed a branch and opened a PR - the "dry run" flag only skipped the merge
```

1. Reproduce: run the agent with the dry-run flag and watch the repo for side effects (new branches, PRs, comments). Expected: confirms the push and PR creation happen despite the flag.
2. Trace the code path and find where the flag is actually checked. Expected: the flag gates only the merge call - push and PR creation run unconditionally upstream of it.
3. Gate every mutating call (push, PR create, comment, label) behind the dry-run flag. Expected: a dry run produces only local output and logs, zero remote writes.
4. Add a regression test: run dry-run in CI against a sandbox repo and assert zero remote refs were created. Expected: the test fails before the fix and passes after.
5. Rename or document honestly: if the mode still opens PRs by design, call it "no-merge", not "dry run". Expected: operators stop trusting the label for isolation.

## Use this when
- A dry run created branches or PRs
- You need to preview what an upgrade agent will do with zero side effects
- The flag's behavior does not match its name
- You are writing the dry-run contract for an agent

## Not for this skill when
- The agent has no dry-run mode at all - that is a feature request
- PRs are opened intentionally as draft previews - that is a design choice, document it
- The side effects happen at merge time rather than before it

## Variant phrasings
- Dry run still opened a PR
- Dry-run flag didn't prevent push
- Agent dry run not side-effect free
- Dry run pushed a branch

## Why it happens
The flag was added at the end of the pipeline, around the merge step, rather than at the boundary where external writes happen. Push and PR creation sit upstream of the merge in the code, so they never see the flag. The name promises isolation; the implementation only promises "will not merge".

## Edge cases
- A dry run that comments "this is a dry run" on a PR is still a side effect - gate comments too
- Fork-based isolation needs the fork to exist and be writable by the agent
- Some agents dry-run against a local repo - verify the remote is never contacted by checking the network log

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_Db3uDhbFeB28PO0B9YpfKw
