fix(capy): a lease records its holder's start identity, so a pid reused after a wake is reclaimed; a skipped session-start upgrade ends fail behind, never ok (GBRA-105, GBRA-106)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
garrytanandcapy-ai[bot] committed 2026-10-16 23:24:02 +00:00
1 parent d7a650fcea
commit 7fa9a1bdcf
10 files changed
+162 -35

No files matched your search

+14 -6
View File
@@ -42,8 +42,10 @@ git clone --single-branch --depth 1 https://github.com/garrytan/gstack.git ~/.lo
refusal of `gstack-upgrade` applies), prints `SELF_UPGRADE: done <old> ->
<new>` and re-execs the new checkout's wrapper, which installs from the
new revision (`GSTACK_CAPY_UPGRADED_FROM` set, so setup is never skipped).
A refusal prints `SELF_UPGRADE: skipped (<reason>)` and the session
continues on the installed revision; the trailer stays the doctor's.
A refusal prints `SELF_UPGRADE: skipped (<reason>)`, and the session is
never certified ok: the trailer is `gstack: fail behind — installed <rev> is
<n> commits behind origin (latest <ver>) and the session-start upgrade was
skipped: <reason>; fix: <command> (UPGRADE_BUSY|UPGRADE_REFUSED)`, exit 1.
`SELF_UPGRADE: none (current)` when nothing is ahead;
`GSTACK_CAPY_SELF_UPGRADE=off` (or `GSTACK_CAPY_AUTO_UPGRADE=0`) prints
`SELF_UPGRADE: disabled (<variable>)`. `--check` never moves the checkout;
@@ -76,10 +78,16 @@ resets.
Several agents sharing one checkout (eight Capy subagents on a machine) hold
workflow leases on it: every `bin/gstack-skill-start` touches
`<git dir>/gstack-leases/<harness pid>` (`bin/gstack-lease touch`; pruned after
120 minutes). `bin/gstack-upgrade`, and so the session-start self-upgrade,
refuses with [UPGRADE_BUSY](troubleshooting.md#upgrade-busy) while a lease
whose pid is alive and outside its own process chain exists;
`bin/gstack-lease list` shows them and `GSTACK_UPGRADE_FORCE=1` overrides.
120 minutes). Each lease records its process's start identity (Linux: boot id
and `/proc` start time; elsewhere `ps -o lstart`), because a pid is reused after
a reboot or a machine wake. `bin/gstack-upgrade`, and so the session-start
self-upgrade, refuses with [UPGRADE_BUSY](troubleshooting.md#upgrade-busy)
while a lease held by a live process outside its own chain exists, naming each
holder as `pid <p> (<age>m <command>)`. A lease whose pid now belongs to another
process, or an identity-less lease from an older gstack past 120 minutes, is
stale: `bin/gstack-lease live` reclaims it (`gstack-lease: reclaimed stale
lease …`). `bin/gstack-lease list` shows `alive|dead|stale`, and
`GSTACK_UPGRADE_FORCE=1` overrides.
## What the installer does
+9 -4
View File
@@ -1403,15 +1403,20 @@ machine, say). Each session start writes a workflow lease,
anything because a lease whose pid is alive and not in its own process
ancestry exists: fast-forwarding would change gstack under a session
mid-workflow. Leases older than 120 minutes are pruned; a lease whose
process has exited never blocks. The upgrader's own session (the pid chain it
process has exited never blocks, and neither does a stale one: each lease
records its process's start identity, so a pid reused after a reboot or a
machine wake (GBRA-105's lease named pid 379, which had become dbus-daemon)
is reclaimed instead of blocking. The upgrader's own session (the pid chain it
runs under) never counts.
**Fix.** Wait for those sessions to finish (`bin/gstack-lease list` shows
every lease with its age and `alive|dead`), then re-run `bin/gstack-upgrade`.
every lease with its age and `alive|dead|stale`; a holder is named as
`pid <p> (<age>m <command>)`), then re-run `bin/gstack-upgrade`.
When you know they are idle, `GSTACK_UPGRADE_FORCE=1 bin/gstack-upgrade`
proceeds. At a Capy session start the same refusal appears as
`SELF_UPGRADE: skipped (live gstack sessions hold this installation: ...)`
and the session continues on the installed revision.
`SELF_UPGRADE: skipped (live gstack sessions hold this installation: ...)`,
and the trailer is `gstack: fail behind — … (UPGRADE_BUSY)`: a session that
could not upgrade is never certified ok.
<a id="upgrade-fetch-failed"></a>
### `gstack-upgrade: could not reach origin (...) (UPGRADE_FETCH_FAILED)`