Capy session: defer the upgrade while a /ship or review run is open; upgrade-path fixes (GST-1677, GST-1658) (#4095)

* capy session: defer the upgrade while a /ship or review run is open; upgrade-path fixes (GST-1677, GST-1658)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* fix: pre-landing review fixes

The pin override releases .setup-lock before an older gstack-upgrade on the local default branch runs, so that copy takes the lock itself instead of refusing against the session's own pid; the no-flock eval-lock test skips visibly instead of returning.

Review-Finding: p1/red-team#1 reader=red-team
Review-Finding: p1/specialist-batched#1 reader=testing
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* docs: troubleshooting names an open /ship or review run as an UPGRADE_BUSY cause

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* changelog: note the older-gstack-upgrade lock release (GST-1658)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
Garry Tanandcapy-ai[bot] authored and GitHub committed 2026-11-06 21:08:42 +00:00
1 parent 688e3ab9d1
commit 0c41ced4fd
8 files changed
+381 -34

No files matched your search

+18 -3
View File
@@ -147,10 +147,25 @@ there is refused with the usual `--for <skill>` fix.
undiverged checkout overrides it (`SELF_UPGRADE: pin overridden (...)
(PIN_UNREASONED)`), switching to the default branch only when that local
branch is absent or fast-forwardable and no other session holds a lease,
and switching back if `bin/gstack-upgrade` refuses. A workflow lease of the
and switching back if `bin/gstack-upgrade` refuses; the switch and the
fast-forward run under the setup lock, which the session takes first and
hands to `bin/gstack-upgrade` (an older copy on the local default branch,
which cannot take it over, gets it released and takes it itself). A
workflow lease of the
current run or a live eval run (gstack-detach's
`~/.gstack/locks/gstack-evals.lock`) defers every self-upgrade
(`UPGRADE_BUSY`). A `--for review-voice` reader gets
`~/.gstack/locks/gstack-evals.lock`, probed with `flock`, else python3 or
perl) defers every self-upgrade (`UPGRADE_BUSY`). So does a /ship or review
run open on the state root, whatever the lease's age (GST-1677): a
ship-budget ledger (`<state root>/ship-runs/<run>/budget.json`) with no
`closed_at` that was written in the last 6 hours, or a review start
(`<state root>/projects/<slug>/.review-starts/<token>.json`) under 120
minutes old that `gstack-review-log --finish` has not consumed. The session
prints `SELF_UPGRADE: deferred (<kind> run <id> (<file>) is open on this
machine, so gstack stays at <version> until it ends ...; fix: <install>
once the run ends (UPGRADE_BUSY))`, keeps the installed revision and stays
ok; `--check` prints `gstack-capy-session: upgrade deferred (...)`.
Below the supported minimum an open run changes nothing: `--check` fails
`revision` and install mode applies the floor as above. A `--for review-voice` reader gets
`stale=<h>h (shared checkout: the lane's install moves it)` and only reports
it. With `GSTACK_UPDATE_CHANNEL=stable` nothing is measured against main.
4. When the fetch fails (offline), the bootstrapper says `remote minimum
+12 -2
View File
@@ -1746,7 +1746,8 @@ yourself; or change the pin in the project.
**Meaning.** An install-mode session start above the supported minimum found
the checkout behind origin and could not fast-forward it: the checkout is
dirty, diverged or pinned (`UPGRADE_REFUSED`), another live session holds a
lease (`UPGRADE_BUSY`), `bin/gstack-upgrade` is missing, or the session is a
lease or a /ship or review run is open on the state root (`UPGRADE_BUSY`,
[deferred](#upgrade-busy)), `bin/gstack-upgrade` is missing, or the session is a
`--for review-voice` reviewer, which never moves a checkout a lane may share
(`UPGRADE_SKIPPED`). Nothing was changed, the doctor certified the installed
revision, and the trailer stays `gstack: ok` with the notes above: a gap
@@ -1769,7 +1770,8 @@ of the oldest commit it lacks, and pinned by `GSTACK_CAPY_SELF_UPGRADE=off`,
`GSTACK_CAPY_AUTO_UPGRADE=0`, a detached HEAD (`--revision`) or another branch,
with no recorded reason. It checked out the default branch where needed and
fast-forwarded. A dirty or diverged checkout is still never moved, and a live
workflow lease or eval run still defers the upgrade (`UPGRADE_BUSY`). On
workflow lease, eval run or open /ship or review run still defers the upgrade
(`UPGRADE_BUSY`). On
`--check` the trailer carries `stale=<h>h` with the install as its fix; unlike a
bare `behind=`, run that fix before the first workflow.
@@ -1826,6 +1828,14 @@ this checkout (UPGRADE_BUSY))` and leaves the
checkout where the run started. Each `gstack-skill-start` renews the lease
and opens a run that its `gstack-skill-end` closes; a lease whose runs are all
closed is idle and never counts (GST-1205).
A run open on the state root defers the Capy install-mode upgrade whatever
its lease's age (GST-1677): `SELF_UPGRADE: deferred (/ship run <id>
(<ledger>) is open on this machine, so gstack stays at <version> until it
ends (R75: upgrades wait for the workflow boundary); fix: <install> once the
run ends (UPGRADE_BUSY))`, for a ship-budget ledger with no `closed_at`
written in the last 6 hours, or `review run <token> (<file>)` for a review
start under 120 minutes old that `gstack-review-log --finish` has not
consumed.
**Fix.** Wait for those sessions to finish (`bin/gstack-lease list` shows
every lease with its age and `alive|idle|dead|stale`; a holder is named as