Follow-up from #272 / PR #275.
This is not a regression, and PR #275 does not introduce it. Nothing has ever periodically re-ensured a local unattended session — the gap is byte-for-byte the same before and after that PR. What changed is only that #275's readiness repair is one more thing that would benefit from a periodic local ensure, which is why the gap is worth writing down now instead of being rediscovered later. The user-visible symptom is strictly less likely after #275 than before it: before, a local Codex pane failed to attach always; after, only if a zmx set fails transiently and nothing calls the ensure again before the human opens the pane.
The gap
A local unattended loop's session is only re-checked when something calls the ensure, and every caller is an edge rather than a heartbeat:
| Caller |
When it runs |
ProjectRegistry load-time ensure |
graph load |
| node creation / promotion |
once, per node |
| local send |
uses sessionExists, not the readiness gate |
sweepRemoteSessions (ProjectRegistry.swift:221) |
every 60s, but filtered to remote projects only |
There is no periodic local equivalent of the remote liveness sweep. That has always been true.
Why it is worth recording now
#272's fix stamps a Codex session with an agent= label in the ensure's run branch, and the pane's attach waits for that label. PR #275 added a repair branch — an ensure that finds the session alive and unlabelled adopts it rather than relaunching it — but the repair can only run when an ensure runs. On a local project, after start-up, that may be never.
Residual failure: if the zmx set fails transiently while the session itself is fine, a local Codex loop stays unattachable until the next graph load, with its pane showing #272's symptom — 60s of waiting, then a bare login shell. Intermittent rather than deterministic, which is the harder version to diagnose.
Options
- Extend the liveness sweep to local unattended sessions (drop the remote-only filter; the local tick is the same
zmx ls grep per unresolved loop the presence poller already pays).
- Or have the pane's readiness wait, on giving up, ask the daemon to ensure rather than only printing that it gave up.
The first is smaller and matches the shape that already exists for remote hosts.
Not urgent
The window is a failed zmx set against a live session, which is rare, and the next graph load clears it.
Follow-up from #272 / PR #275.
The gap
A local unattended loop's session is only re-checked when something calls the ensure, and every caller is an edge rather than a heartbeat:
ProjectRegistryload-time ensuresessionExists, not the readiness gatesweepRemoteSessions(ProjectRegistry.swift:221)There is no periodic local equivalent of the remote liveness sweep. That has always been true.
Why it is worth recording now
#272's fix stamps a Codex session with an
agent=label in the ensure's run branch, and the pane's attach waits for that label. PR #275 added a repair branch — an ensure that finds the session alive and unlabelled adopts it rather than relaunching it — but the repair can only run when an ensure runs. On a local project, after start-up, that may be never.Residual failure: if the
zmx setfails transiently while the session itself is fine, a local Codex loop stays unattachable until the next graph load, with its pane showing #272's symptom — 60s of waiting, then a bare login shell. Intermittent rather than deterministic, which is the harder version to diagnose.Options
zmx lsgrep per unresolved loop the presence poller already pays).The first is smaller and matches the shape that already exists for remote hosts.
Not urgent
The window is a failed
zmx setagainst a live session, which is rare, and the next graph load clears it.