Skip to content

fix(threads): keep un-settled threads active after their PR merges - #61

Merged
gfsaaser24 merged 1 commit into
mainfrom
fix/sticky-unsettle-and-postmerge-activity
Aug 10, 2026
Merged

fix(threads): keep un-settled threads active after their PR merges#61
gfsaaser24 merged 1 commit into
mainfrom
fix/sticky-unsettle-and-postmerge-activity

Conversation

@gfsaaser24

Copy link
Copy Markdown
Owner

The bug

Un-settling a thread whose PR has merged only sticks for minutes. Repro (observed on worktree t3code-767f58a0, PR #54 merged):

  1. Un-settle the thread → the server stamps the keep-active pin (settledOverride: "active").
  2. Open the thread / a session starts → the decider treats this as "real activity" and clears any override back to neutral — including the pin you just set.
  3. The session goes idle (or the reaper ends it) → nothing blocks classification anymore, the override is gone, and the merged-PR rule re-settles the thread instantly.

The thread reads as "done" while follow-up work is still happening in its worktree, and every un-settle buys only one burst of work.

The fix (two parts, intended behavior preserved)

1. Sticky keep-active pin (server, decider.ts, 3 sites). Activity still wakes an explicitly settled thread — blocked work must never stay hidden, that direction is untouched. But activity no longer spends the user's explicit "not done" pin. Only an explicit settle clears it.

2. Post-merge-activity gate (client, threadSettled.ts). Instant merged/closed-PR auto-settle now applies only when the thread went quiet at or before the PR's completion. Activity newer than the PR's updatedAt defers to the ordinary inactivity rule. To feed this, the PR's updatedAt (already fetched from gh, previously dropped) now rides VcsStatusChangeRequest into the web and mobile classifications. When the timestamp is absent (older servers), behavior is unchanged.

The common case is untouched: a thread that goes quiet when its PR merges still settles immediately.

Upstream context

Tests

  • New: decider "keeps a keep-active pin through real activity" (turn start, session start, approval request); effectiveSettled post-merge gate coverage (fresh/stale/quiet/absent-timestamp × merged/closed); GitManager updatedAt forwarding.
  • Updated: 2 decider tests asserting the old clear-on-activity behavior; 5 GitManager deep-equality assertions now include the forwarded field.
  • Green: server orchestration (26), client-runtime threadSettled (180), contracts (226), web logic suites (148), mobile thread lists (71). GitManager: 67/71 — the 4 failures are pre-existing 12–20s timeouts in cross-repo probing tests, confirmed identical on a clean-HEAD baseline run.
  • Typecheck, lint, and format clean across contracts, client-runtime, server, web, mobile.

🤖 Generated with Claude Code

Un-settling a thread whose PR had merged only lasted minutes: any session
start or message cleared the keep-active pin back to neutral, and the
merged-PR rule then re-settled the thread the moment the burst of work went
quiet (the reaper ending the idle session was usually the trigger). The
thread read as "done" while follow-up work was still happening in its
worktree.

Two changes, both preserving the intended lifecycle:

- The explicit keep-active pin is now sticky: activity still wakes an
  explicitly SETTLED thread (blocked work must never stay hidden), but no
  longer spends the user's "not done" pin. Only an explicit settle clears
  it. (decider.ts, three sites)
- Instant merged/closed-PR auto-settle now applies only when the thread
  went quiet at or before the PR's completion. Activity newer than the
  PR's updatedAt defers to the ordinary inactivity rule instead. The PR's
  updatedAt (already fetched from gh) now rides the VCS status contract
  into web and mobile classification. Absent timestamp (older servers)
  keeps the original instant behavior.

Upstream context: pingdotgg#5575 describes the sticky-pin gap;
pingdotgg#5643 proposes a toggle plus sticky un-settle. The
post-merge-activity gate here fixes the default path without a setting.
Registered in SEAM.md as an upstream candidate.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L labels Aug 10, 2026
@github-actions

Copy link
Copy Markdown

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 11.3 KiB 11.3 KiB −28 B (−0.2%) 15.1 KiB
Codex Thread snapshot wire 5.4 KiB 5.5 KiB +7 B (+0.1%) 7.3 KiB
Codex Live turn WebSocket wire 5.9 KiB 5.8 KiB −35 B (−0.6%) 7.8 KiB
Codex Live turn WebSocket decoded 49.7 KiB 49.7 KiB 0 B (0.0%) 66.4 KiB
Codex Live turn messages 16 16 0 (0.0%) 21
Claude Total thread wire 11.3 KiB 11.3 KiB +21 B (+0.2%) 15.1 KiB
Claude Thread snapshot wire 5.5 KiB 5.5 KiB −9 B (−0.2%) 7.3 KiB
Claude Live turn WebSocket wire 5.8 KiB 5.9 KiB +30 B (+0.5%) 7.8 KiB
Claude Live turn WebSocket decoded 50.6 KiB 50.6 KiB 0 B (0.0%) 66.4 KiB
Claude Live turn messages 16 16 0 (0.0%) 21

Baseline: 315f8af · PR result: 1ff162a · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 94.6 KiB
  • Claude decoded thread snapshot: 95.3 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@gfsaaser24
gfsaaser24 merged commit 24d2564 into main Aug 10, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant