Skip to content

fix(session-flow): distinguish a completed background continuation from a failed one - #2115

Merged
kyle-sexton merged 7 commits into
mainfrom
fix/session-flow-stranded-1033
Aug 10, 2026
Merged

fix(session-flow): distinguish a completed background continuation from a failed one#2115
kyle-sexton merged 7 commits into
mainfrom
fix/session-flow-stranded-1033

Conversation

@kyle-sexton

Copy link
Copy Markdown
Contributor

No linked issue

Summary

Discharges an unresolved review thread stranded on merged PR #1033
(PRRT_kwDOTCGFQM6TybdT, "Distinguish completed agents before retaining handoffs"). The
find-handoff skill's background-delivery screening could not tell a background continuation that
finished the work from one that died, so it labelled a completed continuation's save-point a
failed background attempt and surfaced it as the lost handoff.

Fix

The screening rule rechecks a continuation's current state before excluding its save-point — a good
rule, kept. What was wrong is the state read. It keyed on claude agents presence and collapsed
every absence into one branch:

Continuation absent or failed now → keep the candidate, noting the failed background attempt.

claude agents --json lists active sessions only. Verified live this session, not from recall:

  • claude agents --help--all With --json: also include completed background sessions
  • claude agents --json --all on this machine returns 13 sessions; terminal ones carry
    state (done, stopped) and no status, active ones carry status (idle, busy) and no
    state.
  • Same contract this repo already relies on in plugins/claude-ops/skills/lanes/scripts/lane-launcher.sh
    (load_sessions): "claude agents --json (no --all) lists ACTIVE sessions only … completed/terminal
    background sessions are excluded by the CLI (they surface only under --all …)".

So a successfully completed continuation is absent from the bare list and indistinguishable there
from a dead one. The consequence is the reviewer's: the operator is handed a finished
continuation's save-point, invited to redo completed work, and the recent completed candidate can
bury the older manual handoff they were actually looking for.

The recheck now reads claude agents --json --all and resolves four ways instead of two:

current state action
live (active status) exclude — work in progress
terminal, state reports completion exclude — work FINISHED; point at that session's output, not a rerun
terminal, state does not report completion keep — the restart artifact the recheck exists for
absent even from --all UNKNOWN, keep, never called a failure — the --all history is bounded

Keyed on the launched sessionId/id where the launch-verification listing recorded one; the
--name "continue-<topic>" slug stays the ambiguous key it already is at launch time and routes to
UNKNOWN. State values are read as reported rather than against a closed set.

Following the file's existing "Succeeded" means verified-visible pattern, the resolution is stated
once at the step-1 screening site and declared to govern every screening site; the prompt-only
screening site and the Gotchas bullet reference it instead of restating prose that can drift apart
again. evals/evals.json case 8 carried the defective doctrine verbatim in its expectations — it is
corrected, and case 13 (completed-continuation-is-not-a-failed-one) is added for the branch.

Note on the finding's pointers: the claim verified, the pointers did not. The thread anchors at
SKILL.md:84, which is the /loop re-arm paragraph, not the recheck rule; and
lane-launcher.sh:254-257 no longer holds the cited contract — it is now lines 506-510 of that file.
The complaint was evaluated on its substance, and reproduced.

Verification

Pre-fix control (the complaint reproduces on the PRE-fix tree). Two fresh-context agents were
given only the pre-fix prose — the step-1 screening block, and the Gotchas bullet separately — plus
the scenario (verified-visible launch naming this exact file; continuation completed successfully;
claude agents --json returns no entry), with no reviewer text and no hint of the expected answer:

  • step-1 block → "Keep it … Continuation absent or failed now → keep the candidate. The only
    exclusion branch is Continuation still live →The label is noting the failed background attemptNo such instruction exists [distinguishing failed from completed] … It does
    not
    [mention --all, completed sessions, or terminal state]."
  • Gotchas bullet → "the candidate survives screening and is surfaced as a recoverable save-point …
    the operator may resume it — re-running work that already finished hours ago."

Post-fix (same prompts, swapped text). The step-1 agent now refuses the bare---json reading
outright — "Exclusion is only reachable via the Live or Terminal and completed branches,
both of which require a positive presence reading you do not have … re-run the lookup with
--all"
— and, on absence from --all, reports "UNKNOWN, never 'failed.' … report that the
continuation's outcome could not be determined instead of asserting a failed background attempt."

The complaint no longer reproduces.

An adversarial fresh-context verifier was also run against the diff with the rationale withheld and
instructed to refute that the finding is discharged.

scripts/affected-tests.sh --run for this diff; per-plugin changelog parity satisfied
(session-flow 0.21.30.21.4 with its entry).

Related

  • Discharges the unresolved review thread on feat(session-flow): add find-handoff skill to recover a lost handoff (#976) #1033 (PRRT_kwDOTCGFQM6TybdT,
    chatgpt-codex-connector, 2026-07-25) — that PR is already merged, so this lands as a follow-up
    rather than closing an issue.
  • plugins/claude-ops/skills/lanes/scripts/lane-launcher.sh load_sessions — the in-repo statement
    of the claude agents --json / --all contract this fix conforms to (unchanged here).
  • plugins/session-flow/skills/continue-in-background — the producer whose launches this screening
    correlates against (unchanged here).

…om a failed one

find-handoff's background-delivery screening rechecked the continuation's
current state before excluding a save-point, but keyed that recheck on
`claude agents` presence and collapsed every absence into "keep the candidate,
noting the failed background attempt".

`claude agents --json` lists ACTIVE sessions only; a completed background
session is excluded by the CLI and surfaces only under `--all`, carrying a
`state` (observed: done, stopped) where a live one carries a `status`
(observed: idle, busy). Verified this session against `claude agents --help`
and a live `--json --all` sample; it is the same contract claude-ops'
lane-launcher.sh (load_sessions) already relies on.

A finished continuation therefore looked identical to a dead one: the ladder
surfaced its save-point as a lost handoff labelled a failed attempt, inviting
the operator to redo completed work and letting a recent completed
continuation bury the older manual handoff they were actually looking for.

The recheck now reads `claude agents --json --all` and resolves four ways
instead of two: live (exclude, running), terminal-and-completed (exclude,
FINISHED, point at that session's output), terminal-and-not-completed (keep,
the restart artifact the recheck exists for), and absent even from --all
(UNKNOWN, keep, never called a failure, since the --all history is bounded).
Keyed on the launched sessionId where the transcript recorded one; the
continue-<topic> slug stays an ambiguous key that routes to UNKNOWN.

Stated once at the step-1 screening site and governing every screening site,
with the prompt-only site and the Gotchas bullet aligned to it. evals.json
case 8's stale expectation is corrected and a case is added for the
completed-continuation branch.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@cursor

cursor Bot commented Aug 9, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@claude

claude Bot commented Aug 9, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 1m 16s —— View job


Security review complete ✅

  • Gather context (PR diff, changed files)
  • Review changed files for security issues
  • Post findings

Scope reviewed (gh pr diff 2115, 4 files / +102 -19):

  • plugins/session-flow/.claude-plugin/plugin.json — version bump only (0.21.30.21.4)
  • plugins/session-flow/CHANGELOG.md — prose changelog entry
  • plugins/session-flow/skills/find-handoff/SKILL.md — instruction-doc changes to the background-continuation state-recheck rule
  • plugins/session-flow/skills/find-handoff/evals/evals.json — eval fixture text (case 8 updated, case 13 added)

Findings

No security issues found.

This PR is a pure documentation/instruction-prose change to a Claude Code skill, plus matching eval fixtures and a changelog/version bump — there is no executable code, script, hook, or workflow in the diff. Specifically checked for and ruled out:

  • Command injection — the new/changed instructions direct the agent to run a fixed, literal command (claude agents --json --all) with no variable interpolation into a shell string. Session correlation ("key the lookup on the launched session's sessionId/id") is described as matching against structured JSON output for display/decision purposes, not as building a shell command from transcript-derived data. This mirrors the pre-existing, unmodified pattern elsewhere in the same file (<session_id>.jsonl transcript lookups).
  • Untrusted-data / prompt-injection surface — the diff doesn't add any new consumption of transcript content into a command or file path; it only changes how an already-read state/status field from claude agents --json --all JSON output is interpreted (four-way branch instead of two-way).
  • Credential/secret handling — the Handoff origin: redaction-vs-URL-sanitization logic (the one part of this file that handles credential material) is unchanged by this diff.
  • Access control / trust boundary — no changes to hooks, permissions, .mcp.json, or workflow files; claude agents --json --all only enumerates the local user's own sessions on the same machine, which is no broader an information exposure than the existing claude agents --json.
  • Supply chain — no dependency, action-pin, or manifest permission changes beyond the plain semver bump.

Nothing in scope for this lane (unpinned actions, dangerous triggers, excessive permissions, static template-injection) applies — there are no workflow files in this diff.
· branch fix/session-flow-stranded-1033

@claude

claude Bot commented Aug 9, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 4m 54s —— View job


Review complete

  • Gather context (PR diff, CLAUDE.md, REVIEW.md)
  • Understand the request
  • Review changed files for correctness, architecture, error handling, test coverage, maintainability
  • Post findings

This PR discharges a stranded review thread from merged PR #1033: find-handoff's background-delivery screening previously keyed its current-state recheck on bare claude agents presence, so a completed background continuation looked identical to a dead one and was surfaced as a failed attempt. The fix reads claude agents --json --all and resolves the recheck four ways (live / terminal-completed / terminal-not-completed / absent-even-from---all) instead of two, aligning the step-1 screening site, the prompt-only site, and the Gotchas bullet, and adding eval case 13 for the completed-continuation branch.

Changes are scoped entirely to documentation/config surfaces (SKILL.md prose body, evals.json, CHANGELOG.md, plugin.json version bump) — no code paths, so CLAUDE.md's fresh-docs mandate doesn't apply (frontmatter/contract surfaces are untouched; only the skill's prose body changed). Version bump (0.21.30.21.4) matches the new CHANGELOG entry.

Posted 3 inline nits (all 🟡, non-blocking):

  1. SKILL.md:132-140 — the two observed terminal state values (done, stopped) are introduced together without saying which one reports completion; the mapping is only inferable later from a parenthetical. Worth pinning down explicitly given this is exactly the ambiguity class the fix is trying to eliminate.
  2. SKILL.md:160 — the new sessionId/id (from claude agents --json --all) reads similarly to the pre-existing session_id (transcript frontmatter, used throughout the rest of the file for a different purpose). Two different fields from two different sources with near-identical names, used in the same procedure — worth a one-line disambiguation.
  3. evals/evals.json:171-184 — the new eval case (and updated case 8) cover the "live" and "terminal-completed" branches, but neither "terminal-not-completed" (the restart-artifact case the recheck exists for) nor "absent-even-from---all" (UNKNOWN) gets its own scenario — only prose mentions. The absent-from---all branch is the exact misclassification class this PR fixes, so it's the one most worth a dedicated eval.

Verification note: the PR body's live-session verification of claude agents --help/--json --all output and the pre/post-fix agent-reproduction tests are author-claimed; I did not have a claude CLI available in this review environment to independently re-run them, so I did not re-verify those specific claims — I did independently confirm the JSON structural validity of evals.json, ID uniqueness (1–13), the CHANGELOG/plugin.json version parity, and cross-referenced the session_id/sessionId and state-value terminology against the rest of the file.

No correctness bugs or blocking issues found.

Branch: fix/session-flow-stranded-1033

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 80f4febb12

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread plugins/session-flow/skills/find-handoff/SKILL.md Outdated
Comment thread plugins/session-flow/skills/find-handoff/SKILL.md
Comment thread plugins/session-flow/skills/find-handoff/SKILL.md Outdated
Comment thread plugins/session-flow/skills/find-handoff/evals/evals.json
@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown

Claude has reviewed this PR 5 times. The lane skips further automatic reviews after 5; deleting this comment resets the count.

@claude

claude Bot commented Aug 9, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 51s —— View job


Security review complete ✅

  • Gather context (PR diff, changed files)
  • Review changed files for security issues
  • Post findings

Scope reviewed (git diff origin/main...HEAD, 4 files / +102 -19, HEAD 1cc4aaa):

  • plugins/session-flow/.claude-plugin/plugin.json — version bump only (0.21.30.21.4)
  • plugins/session-flow/CHANGELOG.md — prose changelog entry
  • plugins/session-flow/skills/find-handoff/SKILL.md — instruction-doc changes to the background-continuation state-recheck rule
  • plugins/session-flow/skills/find-handoff/evals/evals.json — eval fixture text (case 8 updated, case 13 added)

Findings

No security issues found.

This PR is a pure documentation/instruction-prose change to a Claude Code skill, plus matching eval fixtures and a changelog/version bump — there is no executable code, script, hook, or workflow file in the diff. Specifically checked for and ruled out:

  • Command injection — the new/changed instructions direct the agent to run a fixed, literal command (claude agents --json --all) with no variable interpolation into a shell string. Session correlation ("key the lookup on the launched session's sessionId/id") is described as matching against structured JSON output for display/decision purposes, not as building a shell command from transcript-derived data. This mirrors the pre-existing, unmodified pattern elsewhere in the same file (<session_id>.jsonl transcript lookups).
  • Untrusted-data / prompt-injection surface — the diff doesn't add any new consumption of transcript content into a command or file path; it only changes how an already-read state/status field from claude agents --json --all JSON output is interpreted (four-way branch instead of two-way). No new attacker-controlled input reaches an executable sink.
  • Authorization / trust boundaryclaude agents --json --all only enumerates the local user's own sessions on the same machine (a bounded, self-scoped history), which is no broader an information exposure than the existing claude agents --json it replaces. There's no cross-user or cross-tenant data crossing a boundary here.
  • Credential/secret handling — the Handoff origin: redaction-vs-URL-sanitization logic (the one part of this file that handles credential material) is unchanged by this diff.
  • Supply chain — no dependency, action-pin, or manifest permission changes beyond the plain semver bump; no workflow files touched.

The slug-only session-key ambiguity flagged by Codex (SKILL.md:163) is a real logic/correctness concern worth addressing, but it's a local, single-user, read-only screening heuristic — a wrong branch at worst causes an agent to under- or over-surface its own save-point candidates, not an authorization bypass or data exposure across a trust boundary. Not re-reported here as a security finding.

@claude

claude Bot commented Aug 9, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 4m 10s —— View job


Code review complete

  • Gather context (PR diff, CLAUDE.md, REVIEW.md)
  • Review changed files for correctness, architecture, error handling, test coverage, maintainability
  • Post findings

Scope reviewed (git diff origin/main...HEAD, 4 files / +102 -19): plugin.json (version bump), CHANGELOG.md (prose entry), find-handoff/SKILL.md (the four-way current-state resolution), find-handoff/evals/evals.json (case 8 updated, case 13 added). All changes are to a skill's prose body and its eval fixtures — no frontmatter/contract-surface fields changed, so CLAUDE.md's fresh-docs mandate does not apply here. Version bump (0.21.30.21.4) matches the new CHANGELOG entry. I independently confirmed evals.json parses as valid JSON with unique ids 1–13 (via direct read, not the author's claimed tooling).

The fix itself is sound: replacing the old two-way "live vs. everything-else-is-failed" recheck with a four-way resolution (live / terminal-completed / terminal-not-completed / absent-even-from---all) is the right shape for the bug described, and the same resolution is correctly centralized and cross-referenced from the prompt-only screening site and the Gotchas bullet instead of being restated three times.

Finding posted inline

SKILL.md:163 (🟡, independently confirmed) — the slug-only fallback ("--name doesn't uniquely resolve → UNKNOWN, otherwise use it") treats currently unique as proof of identity, but --all's history is bounded (the file's own reasoning one paragraph up). The session that actually produced a given candidate can age out of that bounded history while a newer launch reusing the same continue-<topic> slug remains — so the slug is now unique but resolves to the wrong session, and the recheck would borrow that unrelated session's live/completed state. This is the same class of misattribution the PR fixes, reached a different way. This independently reproduces @chatgpt-codex-connector's finding on the same line — flagging here as a second, independent confirmation that it's real and worth closing (e.g., slug-only evidence should always be UNKNOWN, regardless of momentary uniqueness).

Already-open, unresolved from the prior code-review-lane pass on this same commit (not re-posted to avoid duplicate inline threads, still outstanding)

  • SKILL.md:140 — which observed state value (done vs. stopped) maps to "completed" is only inferable later, not stated where the two values are first introduced.
  • SKILL.md:160 — new sessionId/id (from claude agents --json --all) vs. pre-existing session_id (transcript frontmatter) are same-sounding, different-source fields used side by side.
  • evals/evals.json:171-184 — no dedicated eval scenario for "terminal-and-not-completed" (the restart-artifact branch) or "absent-even-from---all" (UNKNOWN) — the latter is the exact misclassification class this PR fixes.

Verification notes

  • The PR body's live-session verification of claude agents --help / --json --all output, and the pre/post-fix agent-reproduction tests, are author-claimed and unverified by me — this sandbox blocks running claude agents ... and scripts/affected-tests.sh --run (both require an approval this environment doesn't grant), so I could not independently re-run them.
  • No architecture, error-handling, or atomicity concerns apply — this diff has no code path, no multi-record write, and no security-relevant action for REVIEW.md's mandatory checks to catch.

No blocking issues. One 🟡 correctness nit posted inline; three prior nits remain open from the earlier pass on this same commit.
· branch fix/session-flow-stranded-1033

Comment thread plugins/session-flow/skills/find-handoff/SKILL.md Outdated
Version collision only. Main shipped session-flow 0.22.0 (the bare-alias
removal) while this branch held 0.21.4, so this entry takes 0.22.1 and both
changelog entries are kept in full — they cover unrelated changes.

Verified: no conflict markers remain, plugin.json parses, changelog versions are
monotonic with no duplicates, no MD012.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Aug 9, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 45s —— View job


Security review complete ✅

  • Gather context (PR diff, changed files)
  • Review changed files for security issues
  • Post findings

Scope reviewed (git diff origin/main...HEAD, 4 files / +102 -19, HEAD 0b4d32d):

Findings

No security issues found.

This PR remains a pure documentation/instruction-prose change to a Claude Code skill, plus matching eval fixtures and a changelog/version bump — there is no executable code, script, hook, or workflow file anywhere in the diff. Re-checked against the current HEAD (0b4d32d, post-merge-of-main) with the same reasoning as the earlier passes on this PR, since none of the substantive prose changed between commits — only an unrelated version-number shift (0.21.x0.22.x) from the intervening merge:

  • Command injection — the instructions direct the agent to run a fixed, literal command (claude agents --json --all) with no variable interpolation into a shell string. Session correlation ("key the lookup on the launched session's sessionId/id") is described as matching against structured JSON output for display/decision purposes, not as building a shell command from transcript-derived data. This mirrors the pre-existing, unmodified pattern elsewhere in the same file (<session_id>.jsonl transcript lookups).
  • Untrusted-data / prompt-injection surface — no new consumption of transcript content into a command or file path; the change only alters how an already-read state/status field from claude agents --json --all JSON output is interpreted (four-way branch instead of two-way). No new attacker-controlled input reaches an executable sink.
  • Authorization / trust boundaryclaude agents --json --all enumerates only the local user's own sessions on the same machine, no broader an information exposure than the claude agents --json it replaces. No cross-user or cross-tenant boundary is crossed.
  • Credential/secret handling — the Handoff origin: redaction-vs-URL-sanitization logic (the one part of this file that handles credential material) is unchanged.
  • Supply chain — no dependency, action-pin, or manifest permission changes beyond the plain semver bump; no workflow files touched.

The slug-only session-key ambiguity flagged in review threads (SKILL.md current-state recheck fallback) is a real logic/correctness concern, but it stays a local, single-user, read-only screening heuristic — a wrong branch at worst causes an agent to under- or over-surface its own save-point candidates, not an authorization bypass or cross-boundary data exposure. Not re-reported here as a security finding (out of scope for this security-focused lane).
· branch fix/session-flow-stranded-1033

@claude

claude Bot commented Aug 9, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 3m 12s —— View job


Code review complete

  • Gather context (PR diff, CLAUDE.md, REVIEW.md)
  • Understand the request
  • Review changed files for correctness, architecture, error handling, test coverage, maintainability
  • Post findings

Scope reviewed (git diff origin/main...HEAD, HEAD 0b4d32d): plugin.json (version bump), CHANGELOG.md (prose entry), find-handoff/SKILL.md (the four-way current-state resolution), find-handoff/evals/evals.json (case 8 updated, case 13 added). All four are doc/config surfaces — no frontmatter/contract fields touched, so CLAUDE.md's fresh-docs mandate doesn't apply. I independently confirmed (by reading the files, not by running the author's tooling):

  • evals.json parses as valid JSON with unique, sequential ids 1–13.
  • plugin.json's 0.22.00.22.1 bump matches the new CHANGELOG.md entry, and no other manifest (marketplace.json) needs a matching bump.
  • The find-handoff/SKILL.md content itself is unchanged between the commit two prior review passes already covered (1cc4aaa) and current HEAD — the only diff in between is an unrelated merge that dropped frontmatter name: fields repo-wide (shifting line numbers by −1), so every finding already posted against this file still applies verbatim, just one line higher than where it was originally anchored.
  • The prompt-only screening site (SKILL.md:270-275) and the Gotchas bullet (SKILL.md:472-481) both correctly defer to step 1's four-way resolution rather than restating it — no drift between the three sites.

Note on the PR body: its version-bump claim ("session-flow 0.21.30.21.4") doesn't match the actual diff (0.22.00.22.1) — a stray leftover from an earlier draft, harmless since the real manifest/changelog pair agree with each other.

Still open from the two prior code-review-lane passes on this same content (not re-posted, to avoid duplicate inline threads)

  • SKILL.md:161 — the slug-only fallback still treats a currently unique continue-<topic> match in --all's bounded history as identity. Independently re-verified: the bounded-history reasoning is stated four lines up (line 152's "the --all history is bounded"), so a candidate's true producing session can age out of it while a newer, unrelated launch reusing the same slug remains — that newer session's live/completed state would then be borrowed for the older candidate, the same misattribution class this PR fixes, reached a different way. Raised independently by Codex and twice by Claude on the pre-merge commit; no commit since addresses it.
  • SKILL.md:138 — which of the two observed state values (done, stopped) maps to "completed" is still only inferable from the later "Terminal and not completed" bullet's parenthetical, not stated where the values are first introduced.
  • SKILL.md:158 — new sessionId/id (from claude agents --json --all) vs. pre-existing session_id (transcript frontmatter) remain same-sounding, different-source fields used side by side with no disambiguating note.
  • evals/evals.json:171-186 — still no dedicated eval scenario for "terminal-and-not-completed" (the restart-artifact branch) or "absent-even-from---all" (UNKNOWN) — the latter is the exact misclassification class this PR fixes, and is currently exercised only as a hypothetical inside case 13's expected_output, not as its own tested prompt.

No new correctness, architecture, or maintainability issues found beyond what's already flagged above. The core fix (four-way resolution replacing the old two-way live/failed collapse) is sound and consistently applied across all three screening sites.

Verification note: the PR body's live-session verification of claude agents --help / --json --all output is author-claimed; this environment has no claude CLI available, so I did not re-run it and am not claiming independent confirmation of that specific output.
· branch fix/session-flow-stranded-1033

… which id

Two review nits on find-handoff, both still live at this head.

The two observed terminal `state` values were listed side by side with nothing
saying which one means the continuation finished. That mapping is what the
four-way resolution turns on — `done` sends a candidate down the excluded
"finished" branch and `stopped` down the kept "restart artifact" branch — and it
was only recoverable implicitly, several lines later. Stated inline instead.

`sessionId`/`id` is a `claude agents --json` field and collides by sight with the
`session_id` this file uses everywhere else for transcript frontmatter. A reader
keying the recheck on the wrong one gets no match and reports UNKNOWN. Named the
source explicitly at the point of use.

Prose only; no branch logic changed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Aug 10, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 48s —— View job


Security review complete ✅

  • Gather context (PR diff, changed files)
  • Review changed files for security issues
  • Post findings

Scope reviewed (git diff origin/main...HEAD, 4 files / +105 -19, HEAD b4f18c9):

  • plugins/session-flow/.claude-plugin/plugin.json — version bump only (0.22.00.22.1)
  • plugins/session-flow/CHANGELOG.md — prose changelog entry
  • plugins/session-flow/skills/find-handoff/SKILL.md — instruction-doc changes to the background-continuation current-state recheck (two-way → four-way resolution)
  • plugins/session-flow/skills/find-handoff/evals/evals.json — eval fixture text (case 8 updated, case 13 added)

Findings

No security issues found.

This PR is a pure documentation/instruction-prose change to a Claude Code skill, plus matching eval fixtures and a changelog/version bump — there is no executable code, script, hook, or workflow file anywhere in the diff. Specifically checked and ruled out:

  • Command injection — the instructions direct the agent to run a fixed, literal command (claude agents --json --all) with no variable interpolation into a shell string. The new correlation step ("key the lookup on the launched session's sessionId/id") is described as matching against already-returned structured JSON output, not as building a shell command from transcript-derived data. This mirrors the pre-existing, unmodified pattern elsewhere in this file (<session_id>.jsonl transcript lookups).
  • Untrusted-data / prompt-injection surface — no new consumption of transcript content into a command or file path; the change only alters how an already-read state/status field from claude agents --json --all JSON output is interpreted (four-way branch instead of two-way). No new attacker-controlled input reaches an executable sink.
  • Authorization / trust boundaryclaude agents --json --all enumerates only the local user's own sessions on the same machine, no broader an information exposure than the claude agents --json it replaces. No cross-user or cross-tenant boundary is crossed.
  • Credential/secret handling — the Handoff origin: redaction-vs-URL-sanitization logic (the one part of this file that handles credential material) is unchanged by this diff.
  • Supply chain — no dependency, action-pin, or manifest permission changes beyond the plain semver bump; no workflow files touched.

The slug-only session-key ambiguity flagged in earlier review passes on this same content (SKILL.md's current-state recheck fallback treating a currently unique continue-<topic> match as identity, when --all's bounded history means an unrelated newer session could reuse the slug) is a real logic/correctness concern, but it remains a local, single-user, read-only screening heuristic — a wrong branch at worst causes an agent to under- or over-surface its own save-point candidates, not an authorization bypass or cross-boundary data exposure. Consistent with prior passes on this PR, not re-reported here as a security finding (out of scope for this security-focused lane).
· branch fix/session-flow-stranded-1033

@claude

claude Bot commented Aug 10, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 1m 41s —— View job


Code review complete

  • Gather context (PR diff, CLAUDE.md, prior review threads)
  • Check whether latest commit (b4f18c9) addresses previously-flagged nits
  • Review for any new correctness/maintainability issues
  • Post findings

Scope reviewed: the delta since the last review pass on this PR — commit
b4f18c9,
which touches only find-handoff/SKILL.md (+8/−5, prose-only per its own commit message). All prior
findings on plugin.json, CHANGELOG.md, and evals/evals.json still apply as posted in earlier
passes on this PR; nothing changed in those three files at this head.

Two open nits from earlier passes are now resolved

  • SKILL.md:133 — the done/stopped → completed/not-completed mapping is now stated inline ("done, which reports completion, and stopped, which does not") instead of only being inferable later from the "Terminal and not completed" bullet's parenthetical. Matches that bullet's wording, no drift.
  • SKILL.md:160sessionId/id is now explicitly named as "the claude agents --json field, NOT the session_id this file uses elsewhere for transcript frontmatter," closing the same-sounding-fields ambiguity.

Both edits are prose-only, consistent with the rest of the four-way resolution, and don't touch branch logic — confirmed by reading the surrounding paragraph, not just the diff.

Still open, not re-posted (avoids duplicate inline threads on unresolved findings)

  • SKILL.md:164 — the slug-only fallback ("does not uniquely resolve to one session") still treats currently unique as proof of identity. Raised independently by @chatgpt-codex-connector and twice by Claude on earlier commits at this same location; this commit's own message scopes itself to the two nits above and states "no branch logic changed," so this one is correctly left untouched by it, but it remains unaddressed.
  • evals/evals.json:171-184 — still no dedicated eval scenario for "terminal-and-not-completed" or "absent-even-from---all" (the latter is the exact misclassification class this PR fixes); both are currently exercised only as prose inside case 13's expected_output.

No new issues found in this delta. Both fixed nits close the gap cleanly and are internally consistent with the surrounding four-way resolution.
· branch fix/session-flow-stranded-1033

The recheck declared UNKNOWN only when a slug failed to resolve to exactly one
session, which reads a unique match as identification. It is not.

`--all`'s history is bounded, so the candidate's own session can age out while a
newer same-topic continuation remains. The slug then matches exactly one entry
and that entry is a DIFFERENT session wearing the same name — and the recheck
would report its state as this candidate's, which is the one thing this
four-way resolution exists to prevent.

Uniqueness at snapshot time is not identity across time. UNKNOWN now holds
whenever no `sessionId` was recorded, regardless of match count; only a recorded
ID identifies.

Prose only; no branch logic changed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Aug 10, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 49s —— View job


Security review complete ✅

  • Gather context (PR diff, changed files)
  • Review changed files for security issues
  • Post findings

Scope reviewed (git diff origin/main...HEAD, 4 files / +107 -19, HEAD 2acaeb8):

Findings

No security issues found.

This PR remains a pure documentation/instruction-prose change to a Claude Code skill, plus matching eval fixtures and a changelog/version bump — there is no executable code, script, hook, or workflow file anywhere in the diff. Re-checked against current HEAD (2acaeb8) with the same reasoning as prior passes on this PR:

  • Command injection — the instructions direct the agent to run a fixed, literal command (claude agents --json --all) with no variable interpolation into a shell string. The correlation step ("key the lookup on the launched session's sessionId/id") is described as matching against already-returned structured JSON output for display/decision purposes, not as building a shell command from transcript-derived data. This mirrors the pre-existing, unmodified <session_id>.jsonl transcript-lookup pattern elsewhere in this file.
  • Untrusted-data / prompt-injection surface — no new consumption of transcript content into a command or file path; the change only alters how an already-read state/status field from claude agents --json --all JSON output is interpreted (four-way branch instead of two-way), plus how that JSON's sessionId/id field is correlated against a transcript-recorded ID. No new attacker-controlled input reaches an executable sink.
  • Authorization / trust boundaryclaude agents --json --all enumerates only the local user's own sessions on the same machine, no broader an information exposure than the claude agents --json it replaces. No cross-user or cross-tenant boundary is crossed.
  • Credential/secret handling — the Handoff origin: redaction-vs-URL-sanitization logic (the one part of this file that handles credential material) is unchanged.
  • Supply chain — no dependency, action-pin, or manifest permission changes beyond the plain semver bump; no workflow files touched.

The slug-only session-key ambiguity that Codex and prior Claude passes flagged on this file (the current-state recheck's fallback for an unrecorded launch ID) is addressed in this diff's new text — the recheck now states slug uniqueness "at snapshot time is not identity across time" and routes slug-only evidence to UNKNOWN regardless of match count. That's a correctness fix to a local, single-user, read-only screening heuristic (a wrong branch would at most cause an agent to under/over-surface its own save-point candidates) — not a security boundary, and out of scope for this security-focused lane either way.
· branch fix/session-flow-stranded-1033

@claude

claude Bot commented Aug 10, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 2m 40s —— View job


Code review complete

  • Gather context (PR diff, CLAUDE.md, prior review threads)
  • Check whether latest commit (2acaeb8) addresses previously-flagged nits
  • Review for any new correctness/maintainability issues
  • Post findings

Scope reviewed: the delta since the last code-review pass on this PR (b4f18c9) — commit
2acaeb8
("a unique slug match is not proof of session identity"), which touches only find-handoff/SKILL.md
(+8/−6). Nothing else changed at this head — plugin.json, CHANGELOG.md, and evals/evals.json
are identical to the previously-reviewed b4f18c9 state, so all prior findings on those three files
still stand as posted in earlier passes.

The last open correctness nit is now fixed

SKILL.md:158-170
— the slug-only fallback ("does not uniquely resolve to one session → UNKNOWN") previously treated a
currently unique continue-<topic> match in --all's bounded history as proof of identity, which
@chatgpt-codex-connector and I both flagged independently on the pre-fix commit. This commit rewrites
the rule correctly: identity now requires a recorded sessionId/id; with none recorded the recheck
is UNKNOWN "and that holds even when the --name \"continue-<topic>\" slug matches exactly one
entry"
(line 163), because that entry can be a different, newer session that reused the same slug
after the candidate's own session aged out of the bounded history (line 164-166). "Uniqueness at
snapshot time is not identity across time" (line 166) states the invariant plainly. This closes the
misattribution class cleanly — read it against the surrounding four-way resolution and it's internally
consistent, with no leftover reference to the old two-way collapse anywhere else in the file.

All three findings raised on this PR's earlier commits are now resolved:

  • SKILL.md done/stopped completion mapping — fixed in b4f18c9, author-confirmed.
  • SKILL.md sessionId/session_id disambiguation — fixed in b4f18c9, author-confirmed.
  • SKILL.md slug-only identity fallback — fixed in 2acaeb8 (this commit), verified above.

Still open, not re-posted (avoids a duplicate inline thread on an unchanged block)

evals/evals.json:170-184
— still no dedicated eval scenario for "terminal-and-not-completed" (the restart-artifact branch) or
"absent-even-from---all" (UNKNOWN) — both are exercised only as a hypothetical inside case 13's
expected_output/expectations, not as their own tested prompts. The absent-from---all branch is
the exact misclassification class this PR fixes, so it remains the one most worth a dedicated eval.
Flagged twice already on earlier commits at this same location with no code change since; leaving it
here as a pointer rather than a third identical inline comment.

No new issues found in this delta. The four-way resolution (live / terminal-completed /
terminal-not-completed / absent-even-from---all) is now sound and consistently applied at all three
screening sites, including the slug-identity edge case.

Verification note: the PR body's live-session verification of claude agents --help /
--json --all output is author-claimed; this environment has no claude CLI available, so I did not
re-run it and am not claiming independent confirmation of that specific output.
· branch fix/session-flow-stranded-1033

kyle-sexton and others added 2 commits August 9, 2026 20:26
…the recheck

Uniqueness at snapshot time is not identity across time. `--all`'s history is
bounded — the same boundedness the UNKNOWN branch already rests on — so the
session that produced a candidate can age out while a newer, unrelated launch
reusing the `continue-<topic>` slug is still listed. The slug then resolves
uniquely to the wrong session and its live-or-completed state is borrowed for
the older candidate: the misattribution this rung exists to prevent, reached
from the other direction.

Only an exact `sessionId`/`id` match identifies a session now; slug-only
evidence is always UNKNOWN, uniqueness notwithstanding.

The slug-to-candidate-FILE rule at :119-121 and :475-476 is deliberately
untouched. That one asks which file a continuation delivered, where same-topic
files from one session all match — a different question from session identity,
and correct as written.

Adds the two eval scenarios the four-way resolution had no dedicated case for:
absent-even-from-`--all` (id 14), which also pins the slug rule above, and
terminal-and-not-completed (id 15). Both were previously reachable only as
criteria inside another case's expected output.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The branch had already shipped this fix as 2acaeb8 before I wrote my own —
I edited from a stale local checkout. Origin's wording wins the conflict: it
additionally disambiguates the `claude agents --json` `sessionId`/`id` field
from the `session_id` this file uses for transcript frontmatter, which mine
did not.

What survives from my commit is the part origin does not have: eval cases 14
(absent-from-all is UNKNOWN, which also pins the slug rule) and 15
(terminal-not-completed is the restart artifact).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Aug 10, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 54s —— View job


Security review complete ✅

  • Gather context (PR diff, changed files)
  • Review changed files for security issues
  • Post findings

Scope reviewed (git diff origin/main...HEAD, 4 files / +132 -19, HEAD 61ffa47):

Findings

No security issues found.

This PR remains a pure documentation/instruction-prose change to a Claude Code skill, plus matching eval fixtures and a changelog/version bump — there is no executable code, script, hook, or workflow file anywhere in the diff. The delta since the last review pass on this PR (commit 2acaeb8 → current HEAD) touches only evals/evals.json — two new eval cases (absent-from-all-is-unknown-not-failed, terminal-not-completed-is-the-restart-artifact), each a static JSON object of prompt/expected_output/expectations strings. No new fields, no interpolation, no new data flow into any executable sink — nothing for a security review to flag there.

Re-checked the full diff against the same criteria as every prior pass on this PR:

  • Command injection — the instructions direct the agent to run a fixed, literal command (claude agents --json --all) with no variable interpolation into a shell string. Session correlation ("key the lookup on the launched session's sessionId/id") is described as matching against already-returned structured JSON output, not as building a shell command from transcript-derived data. This mirrors the pre-existing, unmodified <session_id>.jsonl transcript-lookup pattern elsewhere in this file.
  • Untrusted-data / prompt-injection surface — no new consumption of transcript content into a command or file path; the change only alters how an already-read state/status field from claude agents --json --all JSON output is interpreted (four-way branch instead of two-way), plus how that JSON's sessionId/id is correlated against a transcript-recorded ID. No new attacker-controlled input reaches an executable sink.
  • Authorization / trust boundaryclaude agents --json --all enumerates only the local user's own sessions on the same machine, no broader an information exposure than the claude agents --json it replaces. No cross-user or cross-tenant boundary is crossed.
  • Credential/secret handling — the Handoff origin: redaction-vs-URL-sanitization logic (the one part of this file that handles credential material) is unchanged by this diff.
  • Supply chain — no dependency, action-pin, or manifest permission changes beyond the plain semver bump; no workflow files touched (zizmor's advisory lane covers that surface statically and is deferred to, per this lane's scope).

The slug-only session-key ambiguity raised by Codex and prior Claude passes on this file is now fixed in the diff's text (identity requires a recorded sessionId/id; slug-only evidence always resolves to UNKNOWN, "uniqueness at snapshot time is not identity across time"). That was a correctness fix to a local, single-user, read-only screening heuristic — not a security boundary — consistent with how prior passes on this PR scoped it out of this lane.
· branch fix/session-flow-stranded-1033

@kyle-sexton
kyle-sexton merged commit 53a3ff6 into main Aug 10, 2026
33 checks passed
@kyle-sexton
kyle-sexton deleted the fix/session-flow-stranded-1033 branch August 10, 2026 01:39
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