Skip to content

fix(opencode): clean sessionBusyStart on idle and on session.error#40

Merged
lesquel merged 1 commit into
mainfrom
fix/sessionbusystart-lifecycle
May 17, 2026
Merged

fix(opencode): clean sessionBusyStart on idle and on session.error#40
lesquel merged 1 commit into
mainfrom
fix/sessionbusystart-lifecycle

Conversation

@lesquel

@lesquel lesquel commented May 17, 2026

Copy link
Copy Markdown
Owner

Summary

Fixes 2 of the 3 latent bugs tracked in the #25 comment (surfaced by #28's characterization tests, now on main).

sessionBusyStart (a Map<sessionID, startTime>) grew unboundedly:

  • Bug 2 — idle under threshold: the delete lived inside the >10_000ms idle check, so a quick busy→idle cycle never removed the entry. The threshold must gate only the notification, not the cleanup. Now: on idle, always delete the entry if present; notifySessionIdle still fires only if busy lasted >10s.
  • Bug 1 — session.error: session.error never deleted the entry. An errored (no-longer-busy) session left a stale entry that a later idle for a reused ID could misfire on. Now: session.error deletes the entry.

Guarantees

  • Notification semantics byte-preserved (fresh review quoted main-vs-branch identical): notifySessionIdle iff busy >10s; notifySessionError always; busy .set / event emit / audit.log untouched.
  • Idle guard tightened if (started)if (started !== undefined) — closes a theoretical timestamp-0 edge; behaviorally identical for all real Date.now() values.

Testing

  • The test(integrations,notifications): cover native hooks + pipeline #28 characterization tests that asserted the buggy behavior were flipped to assert the fix — verified genuinely RED on main's code, GREEN only with the fix (not tautological). Plus a busy→error→idle no-misfire regression test.
  • bun test 625/0 · bunx tsc --noEmit clean · scope = event.ts + event.test.ts only
  • Independent fresh-context adversarial review: APPROVE — no nits, no blocking (all 5 checks pass).

Independent off main. No overlap with the open #33 wave-2 PRs (#34–39).

Refs #25 (2 of 3 latent items; the pipeline.flush no-op follows in a separate PR).

Two latent bugs (issue #25) surfaced by #28's characterization tests.
The sessionBusyStart Map grew unboundedly:

- Bug 2: the delete was gated inside the >10_000ms idle check, so a
  quick busy→idle cycle never removed the entry. The threshold must
  gate only the notification, not the cleanup. Now: on idle, always
  delete the entry if present; notify only if busy lasted >10s.
- Bug 1: session.error never deleted the entry — an errored (no longer
  busy) session left a stale entry that a later idle for a reused ID
  could misfire on. Now: session.error deletes the entry.

Notification semantics are byte-preserved: notifySessionIdle still
fires iff busy >10s; notifySessionError still always fires with the
same error extraction; busy .set / event emit / audit unchanged. Also
tightened the idle guard `if (started)` → `if (started !== undefined)`
(closes a theoretical timestamp-0 edge).

The #28 characterization tests that asserted the buggy behavior were
flipped to assert the fix (genuinely RED on the old code), plus a
busy→error→idle no-misfire regression test. bun test 625/0, tsc clean.
Independent fresh-context review: APPROVE, no issues (notification
semantics quoted main-vs-branch identical; tests verified non-tautological).

Refs #25
@lesquel lesquel merged commit b0a19b4 into main May 17, 2026
2 checks passed
@lesquel lesquel deleted the fix/sessionbusystart-lifecycle branch May 17, 2026 20:14
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