Skip to content

fix(session-start): time-based dedup as defense in depth (v6.1.5)#49

Merged
intel352 merged 1 commit into
mainfrom
fix/session-start-time-dedup-2026-05-28T1359
May 28, 2026
Merged

fix(session-start): time-based dedup as defense in depth (v6.1.5)#49
intel352 merged 1 commit into
mainfrom
fix/session-start-time-dedup-2026-05-28T1359

Conversation

@intel352
Copy link
Copy Markdown
Contributor

Summary

User reported seeing 9 identical SessionStart hook payloads stacked back-to-back in Codex after telling the model to "resume and wrap up" near the session limit. The per-session_id:source_kind dedup added in v6.1.2 only catches startup-class re-fires when the host populates session_id consistently — Codex's resume/wrap-up lifecycle apparently fires SessionStart multiple times with rotating IDs and source values our existing dedup doesn't anticipate.

  • hooks/session-start: added a 5-second time-window dedup that runs first. If any SessionStart payload was emitted in the last 5 seconds, the new fire short-circuits regardless of payload shape (session_id, source, agent_id, or absence of all three). Defense in depth on top of the existing per-key dedup.
  • 5-second window chosen so legitimate user-driven compacts spaced minutes apart still emit resumption context. Observed bug was 9 fires inside ~1 second.
  • Implementation uses an mtime marker file (session-start-last-emit); both BSD stat -f %m and GNU stat -c %Y paths covered.

Test plan

  • New regression test_session_start_time_dedup_suppresses_rapid_refires: fires 4 SessionStart events with rotating session_ids + mixed startup/compact sources within 1s, asserts exactly one emits.
  • Test isolation: test_session_start_json and test_wrapper_suppresses_unavailable_c_utf8_locale_noise now use isolated tmpdir cwds so the per-cwd state dir doesn't poison subsequent SessionStart tests via the new time dedup.
  • tests/hook-contracts.sh — 51 assertions PASS
  • tests/version-check.sh — manifests agree on 6.1.5
  • Manual rapid-fire scenario: 4 fires with rotating session_ids within 5s → only first emits; 5th fire after sleep 6 → emits normally.

Why not just dedup harder on session_id

Tried that. Codex appears to rotate session_id between SessionStart fires in some lifecycle events, so per-session dedup misses the rapid-fire case. Time dedup is cheap, correct for the observed symptom, and doesn't depend on the host's choice of payload field names.

🤖 Generated with Claude Code

The per-session_id:source_kind dedup added in v6.1.2 only catches the
startup-class re-fire case. Codex was observed firing SessionStart 9+
times in rapid succession near session limits (after a user "resume and
wrap up" instruction) with rotating session_ids and source values that
our existing dedup didn't anticipate. The user's transcript showed 9
identical short-pointer payloads stacked back-to-back.

Added a 5-second time-window dedup that runs before the session-id
dedup. If any SessionStart payload was emitted in the last 5 seconds,
the new fire short-circuits silently regardless of payload shape --
session_id, source, agent_id, or absence of all three.

Window is intentionally short (5s) so legitimate user-driven compacts
spaced minutes apart still emit their resumption context. The observed
bug was 9 fires inside ~1 second; even 1-second window would catch it.

Implementation:
  - Add LAST_EMIT_FILE in STATE_DIR.
  - Before any state-mutating work, check file mtime; if within window,
    exit 0.
  - Touch LAST_EMIT_FILE after emit_additional_context.
  - mtime check uses both BSD (stat -f %m) and GNU (stat -c %Y) forms.

Tests:
  - Added test_session_start_time_dedup_suppresses_rapid_refires that
    fires 4 SessionStart events in rapid succession with rotating
    session_ids and a mix of startup/compact sources, asserts exactly
    one emits.
  - Fixed test_session_start_json and
    test_wrapper_suppresses_unavailable_c_utf8_locale_noise to use
    isolated tmpdir cwds so the per-cwd state dir doesn't poison
    subsequent SessionStart tests via the new time dedup.

Version bump 6.1.4 -> 6.1.5 across all four manifests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@intel352 intel352 merged commit 1cca78a into main May 28, 2026
5 checks passed
@intel352 intel352 deleted the fix/session-start-time-dedup-2026-05-28T1359 branch May 28, 2026 14:02
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