Skip to content

procs: follow a cleared session to the file its process writes now - #17

Merged
yrstm merged 1 commit into
mainfrom
fix/pair-follow
Jul 21, 2026
Merged

procs: follow a cleared session to the file its process writes now#17
yrstm merged 1 commit into
mainfrom
fix/pair-follow

Conversation

@yrstm

@yrstm yrstm commented Jul 20, 2026

Copy link
Copy Markdown
Owner

Defect (diagnosed live on the devbox)

pid 3898138 — a claude session actively mid-conversation — was paired sure:true, how:start-ts to the file it stopped writing on July 7. The board rendered a working agent as an 8-day-idle corpse with the dead file's title, and since status derives from the paired file, its needs-you transitions could never fire. Cause: a long-lived process starts a new session file on every /clear, and the start-ts tier (first-entry timestamp ≈ process start) identifies the first file forever; sticky then re-derives the same wrong answer every draw.

This is the deepest of the "issues with agents" behind the deck complaints: rows the user reads as corpses can be live sessions, and vice versa.

Fix

The start-ts tier follows the trail. When the matched file has a newer unclaimed sibling that:

  • no other live process's start explains (a concurrently-started process claims its own file via its own start-ts — test pins this), and
  • is still being written (followFreshS = 10 min; a trail gone quiet displays as idle either way, so past that the pairing stops guessing — test pins this too),

the process pairs to that newest successor, how:follow, sure:true. PairClaude gains the injected now these mtime comparisons need (§1b-5). No --json shape change; why surfaces the new tier; README's pairing derivation documents it.

Evidence

  • First direct tests for PairClaude (it had none): follow, stale-trail, other-process cases, staged timestamps/mtimes as offsets from injected now.
  • Live A/B (shadow HOME, fresh cache): the mispaired session now shows working · 16s · "Implement Workstream C from t…" with its real token counts, instead of idle · 8d · "/tmp/cmux-drop-…".
  • Local gates green: go test ./... -race, vet, golangci 0 issues, parity, bats, darwin build.

Stacked on #14

Same files (pair.go, board.go), so this PR's base is fix/pairing-dupes; it retargets automatically when #14 merges (merge #14#15#16 → this).

🤖 Generated with Claude Code

A long-lived claude process starts a fresh session file on every
/clear, but the start-ts tier pinned the process to its first file —
whose first-entry timestamp matches the process start — forever, with
sure:true, so sticky re-derived the same wrong answer every draw. A
live, mid-conversation agent rendered as an idle corpse: observed on a
devbox as a 'working right now' session shown idle-8d with the dead
file's title, its needs-you transitions unable to ever fire.

The start-ts tier now follows the trail: when the matched file has a
newer unclaimed sibling that no other live process's start explains
(a concurrently-started process claims its own file via its own
start-ts) and that is still being written (followFreshS, 10min), the
process pairs to that newest successor, marked how:follow. A stale
successor is not followed — both files would display idle anyway, so
past the freshness bound the pairing stops guessing.

PairClaude gains the injected now these mtime comparisons need; first
direct tests for PairClaude cover the follow, stale-trail, and
other-process cases with staged timestamps and mtimes. README's
pairing derivation documents the rule.

Co-Authored-By: Claude Fable 5 <[email protected]>
@yrstm
yrstm changed the base branch from fix/pairing-dupes to main July 21, 2026 00:59
@yrstm
yrstm merged commit 1e2d1da into main Jul 21, 2026
16 checks passed
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