Skip to content

fix: let a handed-off session exit when claude_session_id has moved on - #321

Merged
bborbe merged 2 commits into
masterfrom
fix/handed-off-session-exit
Oct 20, 2026
Merged

bborbe merged 2 commits into
masterfrom
fix/handed-off-session-exit

Conversation

@bborbe

@bborbe bborbe commented Oct 20, 2026

Copy link
Copy Markdown
Owner

Summary

session-self-exit.py resolved the anchor task by claude_session_id alone. When a planning or design session hands its task to an implementation session, that field moves to the new session and the original matches no task — so it can never exit, even after the task goes terminal.

This adds a second resolution path: a task where the session appears in metrics_sessions while claude_session_id names a successor. That branch skips the terminal check, because the session's own work is already on the record and the successor's progress is not its proof. The pane-ownership and open-card guards still refuse.

Surfaces

  • scripts/session-self-exit.py — read_frontmatter now also returns the raw block; new metrics_session_ids reads the nested list the flat reader cannot see; anchor_task returns a fourth handed_off flag; main branches on it and prints SELF-EXIT: exit — handed off to <sid>.
  • scripts/session-self-exit-test.sh — fixtures and cases for a handed-off task while in progress and after completion, the open-card refusal, an unrelated owner, and an id present only in the task body.
  • CHANGELOG.md — ## Unreleased bullet.

Verification

make test — green. session-self-exit: 18 passed.

session-self-exit.py resolved the anchor task by claude_session_id alone, so a session whose task was handed to another session matched nothing and could never exit. It now also resolves a task through metrics_sessions membership, and that branch skips the terminal check because the session's own work is already on the record. The pane-ownership and open-card guards still refuse.
@bborbe
bborbe marked this pull request as ready for review October 20, 2026 12:01

@ben-s-pull-request-reviewer ben-s-pull-request-reviewer Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{
  "verdict": "approve",
  "summary": "PR adds a correct 'handed-off' exit path to session-self-exit.py: when a session's claude_session_id has moved to a successor, the original session can exit if it appears in the task's metrics_sessions. Implementation is correct, tests are comprehensive, and all four pre-identified concerns are either intentional design or minor test gaps that don't affect correctness.",
  "comments": [],
  "concerns_addressed": [
    {
      "concern": "metrics_session_ids() indentation-based state machine could misinterpret edge cases like empty lines",
      "disposition": "not-an-issue",
      "detail": "metrics_session_ids (py:132-151) correctly handles blank lines: the 'not line.strip()' skip preserves in_block state, so a blank line inside metrics_sessions does not end the section. The state machine is only reset by a non-indented line, which is the correct boundary for a YAML list-of-maps structure."
    },
    {
      "concern": "handed_off branch skips terminal_verdict check entirely — session handed off will exit even if task is in abnormal state",
      "disposition": "not-an-issue",
      "detail": "Intentional design per the docstring and comments: 'A handed-off session skips this guard: its own work is on the record.' Tests confirm the behavior: handed_off_task with status=completed phase=done exits, and open-card guard still applies."
    },
    {
      "concern": "anchor_task returns handed_off=False path when claude_session_id matches, even if session also in metrics_sessions",
      "disposition": "not-an-issue",
      "detail": "Correct behavior: when claude_session_id == sid, the session owns the task as its anchor and should use the normal (non-handed-off) exit path. The handed-off path is specifically for when claude_session_id names a different (successor) session. The test 'an id present only in the task body refuses' confirms body-only appearance is rejected."
    },
    {
      "concern": "handed_off_task fixture only tests execution and done phases, not hold or planning",
      "disposition": "not-an-issue",
      "detail": "The handed_off path skips terminal_verdict entirely (phase is irrelevant), so status=hold with handed_off is not a regression risk. The existing test 'hold is parked, not finished' covers hold for the normal path. The handed_off test gaps are minor and don't affect correctness."
    }
  ]
}

@bborbe
bborbe merged commit 20b016e into master Oct 20, 2026
5 checks passed
@bborbe
bborbe deleted the fix/handed-off-session-exit branch October 20, 2026 12:17
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