Skip to content

fix: bridge session isolation — NATS queues, per-chat agents, dedup, cleanup - #1126

Merged
namastex888 merged 1 commit into
devfrom
fix/bridge-session-isolation
Apr 9, 2026
Merged

namastex888 merged 1 commit into
devfrom
fix/bridge-session-isolation

Conversation

@automagik-genie

Copy link
Copy Markdown
Contributor

Summary

Comprehensive fix for genie omni-bridge session isolation defect. Addresses 7 root causes from session mixing trace:

  1. NATS queue groups — ensure only one bridge processes each message
  2. Per-chat agent identity — separate PG records prevent pane_id overwrites
  3. Message dedup cache — prevent JetStream redelivery duplicates
  4. Stale session cleanup — orphan-all on startup instead of per-row recovery
  5. Empty OMNI_TURN_ID coercion — defense-in-depth for CLI fix
  6. Hook scoping for omni-spawned agents — prevent unintended orchestration spawns

Changes

src/services/omni-bridge.ts:

  • Add { queue: 'genie-bridge' } to all 6 NATS subscriptions (G1)
  • Add recentMessageIds dedup cache with 60s TTL + 1000 entry pruning (G4)
  • Replace per-row recovery with markAllOrphaned() (G5)
  • Coerce empty OMNI_TURN_ID with || (G3, defense-in-depth)

src/services/executors/claude-code.ts:

  • Use chat-scoped agent names: ${agentName}:${chatId} (G2)
  • Pass skipHooks: true in omni spawn params (G6)

src/lib/provider-adapters.ts:

  • Add skipHooks?: boolean to SpawnParams (G6)
  • Guard hook injection: if (!params.skipHooks) (G6)

Test Plan

  • All NATS subscriptions have queue group
  • Per-chat agents create separate PG records
  • Message dedup skips duplicate messageIds
  • Session recovery uses orphan-all (no per-row loop)
  • Empty OMNI_TURN_ID handled gracefully
  • Omni-spawned agents don't trigger orchestration hooks

Related

  • Fixes data breach: WhatsApp users mixed in agent sessions (trace 2026-04-09)
  • Complements omni/389 (OMNI_TURN_ID CLI fix)

@coderabbitai

coderabbitai Bot commented Apr 9, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 5d9b7748-ce6a-4850-9035-f0d2ae527ff6

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/bridge-session-isolation

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@namastex888
namastex888 merged commit c6f5794 into dev Apr 9, 2026
5 checks passed

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces a skipHooks parameter to avoid orchestration side-effects for omni-originated sessions and implements NATS message deduplication within the OmniBridge to handle potential JetStream redeliveries. Additionally, it simplifies the session recovery process by orphaning all active sessions upon startup and adopts NATS queue groups for better message distribution. Feedback was provided regarding the efficiency of the deduplication cache pruning logic, suggesting an early exit from the cleanup loop to take advantage of the insertion order in JavaScript Maps.

Comment on lines +601 to +606
if (this.recentMessageIds.size > 1000) {
const cutoff = Date.now() - 60_000;
for (const [id, ts] of this.recentMessageIds) {
if (ts < cutoff) this.recentMessageIds.delete(id);
}
}

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.

medium

The dedup cache pruning logic iterates through the entire Map every time a message arrives once the size threshold is exceeded. Since JavaScript Map objects preserve insertion order, and entries are added with the current timestamp, the oldest entries are always at the beginning. You can optimize this by breaking the loop as soon as a non-stale entry is encountered, avoiding unnecessary iterations over the rest of the cache. The use of hardcoded limits here is acceptable as an intentional cap to prevent memory growth.

          if (this.recentMessageIds.size > 1000) {
            const cutoff = Date.now() - 60_000;
            for (const [id, ts] of this.recentMessageIds) {
              if (ts < cutoff) {
                this.recentMessageIds.delete(id);
              } else {
                break;
              }
            }
            if (this.recentMessageIds.size > 2000) {
              for (const [id] of this.recentMessageIds) {
                this.recentMessageIds.delete(id);
                if (this.recentMessageIds.size <= 1000) break;
              }
            }
          }
References
  1. It is acceptable to use hardcoded numeric limits (magic numbers) in non-critical fallback logic, especially when they serve as intentional caps to prevent performance issues like excessive I/O.

@namastex888
namastex888 deleted the fix/bridge-session-isolation branch April 10, 2026 16:17
namastex888 added a commit that referenced this pull request Apr 11, 2026
fix: bridge session isolation — NATS queues, per-chat agents, dedup, cleanup
namastex888 pushed a commit that referenced this pull request Apr 12, 2026
All six wishes have their deliverables merged to dev via the PRs listed
below. Moving them from active tracking into _archive/ keeps the
wish directory scoped to in-flight and draft work.

| Wish                        | Shipped via            |
|-----------------------------|------------------------|
| velocity-dashboard          | #1142 + #1143 (hotfix) |
| fix-ghost-approval-p0       | #1134                  |
| perfect-spawn-hierarchy     | #1133                  |
| brain-help-passthrough      | #1129                  |
| scaffold-auto-memory        | #1128                  |
| unify-bridge-revamp-skills  | #1125 + #1126 + #1127  |

No code changes — purely a directory reorganization. Wish artifacts
remain readable at .genie/wishes/_archive/<slug>/WISH.md for historical
reference.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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.

2 participants