Skip to content

fix(session-flow): classify automated, Desktop and orphaned sessions in audit-sessions - #6179

Merged
cursor[bot] merged 3 commits into
mainfrom
cursor/audit-sessions-classify-e44b
Oct 4, 2026
Merged

cursor[bot] merged 3 commits into
mainfrom
cursor/audit-sessions-classify-e44b

Conversation

@kyle-sexton

@kyle-sexton kyle-sexton commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

Summary

/session-flow:audit-sessions counted headless and Agent SDK sessions in its medians and findings, flagged a single interrupt, missed Claude Desktop prompts as typed turns, and would have collected a set-aside .orphaned- transcript as a second session. This fixes all four (findings E4, E6, E7, I6 of #6074).

Fix

  • E4: collect stores each transcript's entrypoint values in entrypoints (or ["unknown"]). Sweep sets aside a session whose entrypoints are all sdk-cli/sdk-ts/sdk-py (census.session_class) and reports automated_set_aside and unclassified in the window, the summary and the markdown header. Sessions with no known entrypoint stay in. Drift still reads every record. A new canary, key_path:user:entrypoint, feeds tokens.main, tokens.sub, time.active_s and human.turns. No new flag.
  • E6: the tools.interrupts threshold goes from 0 to 1, the store's own p90 (confirmed below).
  • E7: the shared transcript_reader.typed_text() accepts an origin.kind: human record whatever its promptSource, after dropping one leading <system-reminder> block. is_typed_turn() wraps it. Collect excerpts the stripped text. CLI records are unchanged, and /session-flow:retro benefits too. RECORD_TYPES is untouched (feat(session-flow): teach the transcript reader eight current record types #5931 owns it).
  • I6: collect skips any *.orphaned-* stem and counts it in skipped_orphaned.
  • reference/store-layout.md documents the field and population in pointer form. session-flow 0.48.6 with a CHANGELOG entry.

Maintainer-confirms decisions

Made on 2026-10-04 by frontier review (Claude Opus 5.5), under the owner's delegation of human-gate items:

  1. Sessions with no known entrypoint stay in the medians and are counted as unclassified. Excluding them would drop records whose transcripts Claude Code has already swept, which is the history the store exists to keep. The group is small: the version bump re-reads every transcript still on disk, and the rest age out of the 180-day retention.
  2. Classifying temp-sandbox sessions by cwd is left out. The issue offers it only as a cheaper first step before a re-collect, which happens anyway. Headless sandbox runs already carry entrypoint: sdk-cli, and a temp-path rule would also set aside interactive scratch sessions. After merge, compare the first sweep's automated_set_aside on the maintainer's machine with the issue's 245; a result near 125 would mean that machine's sandboxes are not sdk-cli and the cwd step is needed.
  3. The key_path:user:entrypoint canary feeds tokens.main, tokens.sub, time.active_s and human.turns: the four metrics whose pooled and interactive-only medians the 2026-10-03 audit compared, all of which moved. Widen the feeds if a later comparison shows another metric moving (the canary's basis text and the CHANGELOG now say exactly that).
  4. The Desktop typed-turn fix applies only to origin.kind: human records, as the issue scopes it. No CLI typed or queued record starts with a reminder (0 of 2,337), and headless prompts carry no origin, so neither CLI nor headless counts change.
  5. The tools.interrupts threshold is confirmed at 1. It is the store's own p90, the rule every threshold in sweep-rules.json follows. 57 of the 81 sessions threshold 0 flagged had a single interrupt, and threshold 1 flags 24 of 764.

Verification

Related

Closes #6076
Part of #6074. Coordinates with #5931 (same reader file, no overlap in record types) and #5818.

Open in Web Open in Cursor 

cursoragent and others added 2 commits October 4, 2026 03:27
…in audit-sessions (#6076)

Store each session's transcript entrypoint values and take sweep medians and
findings over interactive sessions, counting the automated ones set aside.
Raise the tools.interrupts threshold to 1, count Claude Desktop prompts
(origin.kind human, promptSource sdk) as typed turns after one leading
system-reminder block, and skip set-aside .orphaned- transcripts in collect.

Co-authored-by: ksextonmelodic <ksextonmelodic@gmail.com>
Co-authored-by: ksextonmelodic <ksextonmelodic@gmail.com>
@kyle-sexton
kyle-sexton marked this pull request as ready for review October 4, 2026 04:04
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-04T04:08:58.514596Z 083967c Draft marked ready
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@claude

claude Bot commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

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


Security review — /review:security-review

  • Gather context (PR diff, changed files, custom instructions)
  • Invoke /review:security-review per the custom instructions
  • Post findings

No security issues found.

Scope reviewed: all 13 changed files in this PR (session-flow audit-sessions/transcript_reader changes), diffed against origin/main at head 083967c.

Notes from the pass:

  • transcript_reader.py typed_text(): the new LEADING_REMINDER_RE match is anchored (.match, non-greedy, single application) — no ReDoS, and it strips only one leading reminder block before the existing INJECTED_PREFIXES/INTERRUPT_RE checks still run on the remainder, so a second reminder, an injected-prefix tag, or an interrupt marker after the stripped block is still correctly rejected (covered by the new parametrized tests). Relaxing the promptSource check for origin.kind == "human" only widens which records can become "typed," which is an audit-classification concern, not a trust-boundary one: the redaction pipeline (Scrubber/redact.Redactor) that stores excerpts is untouched, so nothing here creates a new path for unredacted secrets to reach the store.
  • census.py _label() already bounds any entrypoint value to CENSUS_LABEL = [A-Za-z0-9_.:-]{1,64} before it's stored, falling back to <other> — so the new entrypoints field can't be used to smuggle arbitrary/oversized transcript text into the store.
  • collect.py orphaned-file skip is a substring check (ORPHANED in main.stem) over locally-written transcript filenames only; this tool's trust boundary is the operator's own machine, so no new exploit path crosses a boundary.
  • Checked the diff against the Gate 0 protected classes (irreversible-action, secret-handling, data-integrity, external-publication, legal-compliance, agent-authority) per the instruction-surface lens — the tools.interrupts threshold change (0→1) and the INJECTED_PREFIXES/redaction lists are unchanged in content and neither removes a guardrail; the threshold bump is a documented, data-justified reporting-sensitivity tune, not a security control.
  • No GitHub Actions workflow files are touched by this PR.

@claude

claude Bot commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

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


Claude is reviewing this PR

Code review (/review:code-review lane)

Scoped the review to the PR's actual two commits (ef35a41^..083967c1), which match the 13 files
listed for this PR. No security findings in scope here — this repo runs a separate security lane
(folded in here only if that lane is absent, which doesn't apply).

No blocking or high-confidence findings. I traced each of the four fixes against its tests and
didn't find a correctness gap that clears this lane's bar:

  • E4 (session_class, entrypoints) — census.py#L115-L124
    correctly treats a record with no known entrypoint as unknown (not automated), and mixed
    interactive+SDK entrypoints as interactive. Confirmed drift is computed in
    sweep.py#L343
    before the automated-session filter at line 354, so drift still reads every record as claimed.
  • E6 (interrupt threshold 0→1) — mechanical, matches the new tests.
  • E7 (Desktop typed turns) — transcript_reader.py#L184-L200
    scopes the promptSource-ignoring and reminder-stripping to origin.kind == "human" only, so
    CLI records (kind absent) are provably unchanged — verified against the new
    cli-reminder-led/cli-typed-reminder-led test cases. collect.py now passes the stripped
    text into _typed_turn for excerpts, matching the PR's claim.
  • I6 (orphaned transcripts) — the .orphaned- stem check in collect.py runs ahead of the
    --session filter and is counted unconditionally, matching test_orphaned_transcript_is_not_a_second_session.

One pre-existing (not introduced by this diff) rough edge, below this lane's bar since the touched
lines don't own it: collect.py's self.interrupts[side] counter
(collect.py#L372-L382)
still matches INTERRUPT_RE against the raw (un-stripped) text, so a Desktop interrupt record
prefixed with a <system-reminder> block would stay uncounted by tools.interrupts even though
typed_text correctly recognizes the equivalent typed-turn case. That line isn't touched by this
PR, so it's out of scope here, but worth a follow-up if Desktop interrupts turn out to carry a
leading reminder in practice.

Verification: I confirmed the diff set and read every changed line; pytest could not be run in
this sandbox (no bash approval available), so the PR's stated "18 new cases fail on main, 258 pass
after" and the lint/typos/markdownlint/gitleaks claims are author-claimed and not independently
verified by me here.

@github-actions

github-actions Bot commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

claude-security-review has reviewed this pull request through 083967c; a later push is reviewed from there.

@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: 083967c1ab

ℹ️ 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/audit-sessions/scripts/collect.py
@github-actions

github-actions Bot commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

claude-review has reviewed this pull request through 083967c; a later push is reviewed from there.

…ollect (#6076)

Co-authored-by: ksextonmelodic <ksextonmelodic@gmail.com>
@cursor
cursor Bot added this pull request to the merge queue Oct 4, 2026
Merged via the queue into main with commit f334dec Oct 4, 2026
21 checks passed
@cursor
cursor Bot deleted the cursor/audit-sessions-classify-e44b branch October 4, 2026 05:35
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.

fix(session-flow): classify automated, Desktop and orphaned sessions in audit-sessions

2 participants