Skip to content

fix(channels): thread workspace identity through channel events to prevent cross-workspace persistence#2633

Open
M3gA-Mind wants to merge 3 commits into
tinyhumansai:mainfrom
M3gA-Mind:fix/channel-events-workspace-identity
Open

fix(channels): thread workspace identity through channel events to prevent cross-workspace persistence#2633
M3gA-Mind wants to merge 3 commits into
tinyhumansai:mainfrom
M3gA-Mind:fix/channel-events-workspace-identity

Conversation

@M3gA-Mind
Copy link
Copy Markdown
Contributor

@M3gA-Mind M3gA-Mind commented May 25, 2026

Summary

  • Add workspace_dir: PathBuf to DomainEvent::ChannelMessageReceived and ChannelMessageProcessed so publishers carry workspace identity at event creation time.
  • Thread ctx.workspace_dir into all three publish_global call sites in channels/runtime/dispatch.rs.
  • Add workspace identity guards in ConversationPersistenceSubscriber and TelegramRemoteSubscriber; mismatched-workspace events are silently dropped with a debug log, preventing cross-workspace JSONL writes.

Problem

ConversationPersistenceSubscriber (and TelegramRemoteSubscriber) captured workspace_dir at registration time with no way to tell whether an in-flight event came from the current workspace or a stale one. When login/workspace switched while ChannelMessageReceived / ChannelMessageProcessed events were still being processed, the subscriber wrote them into the wrong workspace's JSONL store.

Solution

Thread explicit workspace identity through the two affected DomainEvent variants so every subscriber can make a local decision to accept or reject. The PathBuf type was chosen because workspace identity is already represented as a filesystem path throughout the codebase — no new abstraction needed. Mismatched events are dropped before any store write occurs.

Submission Checklist

If a section does not apply to this change, mark the item as N/A with a one-line reason. Do not delete items.

  • Tests added or updated (happy path + at least one failure / edge case) per Testing Strategy
  • Diff coverage ≥ 80% — changed lines (Vitest + cargo-llvm-cov merged via diff-cover) meet the gate enforced by .github/workflows/coverage.yml. Run pnpm test:coverage and pnpm test:rust locally; PRs below 80% on changed lines will not merge.
  • N/A: Coverage matrix updated — no new feature rows; this is a bug fix to existing channel event infrastructure with no new user-visible features.
  • N/A: All affected feature IDs from the matrix are listed in the PR description under ## Related — no matrix feature IDs map to the channel event workspace routing fix.
  • No new external network dependencies introduced (mock backend used per Testing Strategy)
  • N/A: Manual smoke checklist updated — no release-cut surfaces changed (internal event bus / subscriber logic only).
  • Linked issue closed via Closes #NNN in the ## Related section

Impact

  • Desktop only. Pure Rust core event bus change — no UI or Tauri shell changes.
  • Prevents silent data corruption when a workspace switch races with in-flight channel event processing.
  • No performance impact: PathBuf::clone() at publish is one allocation per event on an already-async broadcast path.

Related

Closes #2602

  • Follow-up: none required.

AI Authored PR Metadata (required for Codex/Linear PRs)

Keep this section for AI-authored PRs. For human-only PRs, mark each field N/A.

Linear Issue

  • Key: N/A
  • URL: N/A

Commit & Branch

  • Branch: fix/channel-events-workspace-identity
  • Commit SHA: 8c13e6d5211416174333e3682b2354165c0671db

Validation Run

  • pnpm --filter openhuman-app format:check
  • pnpm typecheck — 4 pre-existing iOS module errors on upstream/main (confirmed present before these changes by stashing and re-running)
  • Focused tests: cargo test -p openhuman --lib memory_conversations::bus (13 passed), cargo test -p openhuman --lib channels::providers::telegram::bus (6 passed), full cargo test -p openhuman --lib (9492 passed)
  • Rust fmt/check (if changed): cargo fmt --all -- --check clean, cargo check --manifest-path Cargo.toml clean
  • N/A: Tauri fmt/check (if changed): no Tauri shell changes in this PR.

Validation Blocked

  • command: pnpm build / pnpm compile
  • error: TS2307: Cannot find module 'qrcode.react' (and 3 other iOS experimental deps)
  • impact: Pre-existing on upstream/main; confirmed by stashing changes and reproducing identically. Not introduced by this PR.

Behavior Changes

  • Intended behavior change: Channel conversation events are now discarded by workspace-scoped subscribers when the event's workspace_dir does not match the subscriber's binding, instead of silently writing to the wrong workspace store.
  • User-visible effect: None during normal single-workspace use. Prevents data corruption on workspace switch.

Parity Contract

  • Legacy behavior preserved: All existing call sites updated; no behavior change for matching-workspace events.
  • Guard/fallback/dispatch parity checks: 11 new tests cover matching-workspace (positive control), stale-workspace drop, mid-conversation workspace switch race, multiple stale workspaces, and correct-after-stale ordering.

Duplicate / Superseded PR Handling

  • Duplicate PR(s): None
  • Canonical PR: This PR
  • Resolution: N/A

Summary by CodeRabbit

  • Bug Fixes

    • Enforced workspace isolation: channel message events now include workspace identity and subscribers (including persistence) drop mismatched-workspace events to prevent cross-workspace state corruption.
  • Tests

    • Updated and added unit/integration tests verifying workspace-identity guards for receive/process/persistence flows.
    • Strengthened E2E assertions around session establishment after re-login/reset.
  • Documentation

    • Expanded event docs describing the workspace-scoped event contract and workspace identity requirements.

Review Change Stack

@M3gA-Mind M3gA-Mind requested a review from a team May 25, 2026 12:40
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 25, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Threads workspace_dir through ChannelMessageReceived/ChannelMessageProcessed; publishers attach ctx.workspace_dir and workspace-scoped subscribers (Telegram, persistence) validate and drop events whose workspace_dir differs from their configured workspace.

Changes

Workspace-identity event contract and guards

Layer / File(s) Summary
Event schema and contract
src/core/event_bus/events.rs, src/core/event_bus/events_tests.rs
DomainEvent::ChannelMessageReceived and ChannelMessageProcessed now include workspace_dir: PathBuf. Top-file docs define the workspace-scoped event contract and tests were updated to include workspace_dir fixtures.
Channel dispatch publishes workspace context
src/openhuman/channels/runtime/dispatch.rs
process_channel_message emits ChannelMessageReceived and ChannelMessageProcessed with ctx.workspace_dir across base, overflow, and completion emission paths.
Telegram subscriber workspace filtering
src/openhuman/channels/providers/telegram/bus.rs, src/openhuman/channels/providers/telegram/bus_tests.rs
TelegramRemoteSubscriber::handle now validates workspace_dir on received/processed events and early-returns (debug log) on mismatch. New tests assert set/clear busy-state only for matching workspace and that stale events are ignored.
Conversation persistence workspace filtering with comprehensive tests
src/openhuman/memory_conversations/bus.rs
ConversationPersistenceSubscriber::handle validates workspace_dir and drops mismatched events before persisting. Existing tests updated and a large suite added covering matching/mismatched events, workspace-switch races, multiple stale workspaces, and recovery.
Integration test with workspace context
src/openhuman/channels/routes_tests.rs
Updated integration test to include workspace_dir from the temp test directory when constructing ChannelMessageReceived.
Memory docs
.claude/memory.md
Documented channel event workspace routing contract and recorded related test/compile notes.
E2E assertions tightened
app/test/e2e/specs/mega-flow.spec.ts
Converted several /auth/me waits into explicit assertions; clarified Scenario 4 comment about re-login establishing a fresh session.

Sequence Diagrams

sequenceDiagram
  participant Dispatch as Channel Dispatch
  participant EventBus as Event Bus
  participant TelegramSub as Telegram Remote Subscriber
  participant PersistSub as Conversation Persistence Subscriber
  participant Store as Conversation Store
  Dispatch->>EventBus: publish ChannelMessageReceived{workspace_dir: A}
  par Telegram handling
    EventBus->>TelegramSub: deliver ChannelMessageReceived{workspace_dir: A}
    TelegramSub->>TelegramSub: extract & validate workspace_dir
    alt matches
      TelegramSub->>TelegramSub: set busy state
    else stale
      TelegramSub->>TelegramSub: debug log & drop
    end
  and Persistence handling
    EventBus->>PersistSub: deliver ChannelMessageReceived{workspace_dir: A}
    PersistSub->>PersistSub: extract & validate workspace_dir
    alt matches
      PersistSub->>Store: persist_channel_turn
    else stale
      PersistSub->>PersistSub: debug log & drop
    end
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • graycyrus
  • senamakel

Poem

🐰 I hop through workspaces, careful and spry,
threading paths in events as they flutter by.
Stale notes I drop with a tidy debug cheer,
so messages persist where their workspace is clear.
A little hop, a test, and all states align.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding workspace identity threading through channel events to prevent cross-workspace persistence. It directly reflects the core objective.
Linked Issues check ✅ Passed The PR comprehensively addresses all coding requirements from issue #2602: adds workspace_dir to events, threads it through publishers, implements workspace-identity guards in subscribers, includes regression test coverage, and documents the event contract.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the linked issue #2602. The e2e test updates strengthen session assertions which support workspace routing validation. The .claude/memory.md documentation aligns with the fix scope.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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

coderabbitai[bot]
coderabbitai Bot previously approved these changes May 25, 2026
@coderabbitai coderabbitai Bot added the working A PR that is being worked on by the team. label May 25, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/test/e2e/specs/mega-flow.spec.ts`:
- Around line 240-243: The waitForMockRequest('GET', '/auth/me', 10_000) call
can silently return undefined on timeout; change the test to explicitly assert
the returned value and fail fast with diagnostic output: call waitForMockRequest
and if it returns undefined throw an Error that includes a summary of recent
mock request logs and call dumpAccessibilityTree() (or include its output) to
aid debugging; apply the same explicit assertion+diagnostic pattern for the
other occurrence of waitForMockRequest in this spec so Composio RPCs never
proceed when /auth/me wasn't observed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 84438ee8-3f80-4e95-bc53-e81dda0c420a

📥 Commits

Reviewing files that changed from the base of the PR and between 8c13e6d and 01dadd8.

📒 Files selected for processing (1)
  • app/test/e2e/specs/mega-flow.spec.ts

Comment thread app/test/e2e/specs/mega-flow.spec.ts Outdated
Copy link
Copy Markdown
Contributor Author

@M3gA-Mind M3gA-Mind left a comment

Choose a reason for hiding this comment

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

Walkthrough

This PR threads a workspace_dir: PathBuf field through two DomainEvent variants (ChannelMessageReceived and ChannelMessageProcessed) so that channel-event subscribers can reject events that originated from a different workspace. Both active subscribers — memory_conversations/bus.rs and channels/providers/telegram/bus.rs — gain an early-return guard that compares the event's workspace_dir against the subscriber's own binding and drops the event if they differ. The implementation is completed with 11 new workspace-identity tests, updated existing test constructions, and an E2E fix in mega-flow.spec.ts that adds a missing GET /auth/me wait so composio RPC calls no longer race against session-store completion.


Change Summary

File Change
src/core/event_bus/events.rs Added workspace_dir: std::path::PathBuf field to ChannelMessageReceived and ChannelMessageProcessed; added module-level doc section
src/openhuman/channels/runtime/dispatch.rs Populated workspace_dir at all 3 publish_global call sites from ctx.workspace_dir
src/openhuman/memory_conversations/bus.rs Added workspace guard in both handled variants; 7 new tests + 4 updated event constructions
src/openhuman/channels/providers/telegram/bus.rs Added workspace guard for ChannelMessageReceived; 4 new tests + 2 updated event constructions
src/core/event_bus/events_tests.rs Updated 2 event constructions with workspace_dir
src/openhuman/channels/routes_tests.rs Updated 1 event construction using the real tempdir path
app/test/e2e/specs/mega-flow.spec.ts Added waitForMockRequest('GET', '/auth/me', 10_000) after deep-link auth in Scenarios 4 and 11

Per-File Analysis

src/core/event_bus/events.rs

The new workspace_dir field is correctly placed on both channel-message variants. Using std::path::PathBuf (fully qualified) keeps the events file free of a use import and matches the type used throughout the codebase for workspace paths. The module-level doc section clearly documents the guard contract, which is valuable given that DomainEvent is #[non_exhaustive].

src/openhuman/channels/runtime/dispatch.rs

All three publish_global call sites are updated. ctx.workspace_dir.as_ref().clone() is the correct idiom for Arc<PathBuf>PathBuf. No publish site was missed.

src/openhuman/memory_conversations/bus.rs

The guard pattern (if *workspace_dir != self.workspace_dir { log::debug!(...); return; }) is idiomatic and consistent. The debug log includes both paths, enabling correlation in traces. Test coverage is thorough: 7 new cases cover matching workspace (persists), mismatching workspace (drops), and both event variants. The 4 updated existing constructions correctly include workspace_dir.

Note: CONVERSATION_PERSISTENCE_HANDLE is a static OnceLock<SubscriptionHandle> — this is pre-existing design that prevents re-registration if the core process restarts within the same OS process (e.g. restart_core_process). The workspace guard added here does not change or worsen this behavior, but it is worth tracking as a follow-on.

src/openhuman/channels/providers/telegram/bus.rs

Guard is correctly applied using tracing::debug! (consistent with the existing logging style in this file). 4 new tests mirror the memory_conversations pattern. Both updated existing event constructions include the workspace_dir field.

src/core/event_bus/events_tests.rs and src/openhuman/channels/routes_tests.rs

Mechanical updates. routes_tests.rs correctly uses the actual tempdir.path().to_path_buf() rather than a placeholder, which is good hygiene.

app/test/e2e/specs/mega-flow.spec.ts

The root cause was correct: auth_store_session internally calls GET /auth/me before writing the session token to disk, so composio RPC calls issued immediately after POST /telegram/login-tokens/ could race. Adding await waitForMockRequest('GET', '/auth/me', 10_000) is the right fix and matches the pattern already used in Scenario 1.


Actionable Inline Comments

app/test/e2e/specs/mega-flow.spec.ts — Scenarios 4 and 11: assert the waitForMockRequest return value

Scenario 1 (the reference pattern) assigns and asserts the result:

const me = await waitForMockRequest('GET', '/auth/me', 10_000);
expect(me).toBeDefined();

Scenarios 4 and 11 fire-and-forget the call. If the wait times out and returns undefined, the test silently continues and the composio race condition will resurface in a harder-to-diagnose way. Prefer the asserting form so a timeout fails visibly at the wait site instead of at a downstream assertion.


Nitpicks

  • src/openhuman/memory_conversations/bus.rs log: the debug message doesn't include message_id or channel — both are available in the destructure and would help correlate log lines to specific events in traces.
  • src/openhuman/channels/providers/telegram/bus.rs: The ChannelMessageProcessed arm uses .. to ignore workspace_dir (telegram bus only handles ChannelMessageReceived). A short comment noting that ChannelMessageProcessed is intentionally unguarded here would help future readers.

Summary

The implementation is correct and complete. All publish sites are updated, both active subscribers are guarded, workspace identity is tested at unit level, and the E2E race is fixed. The one actionable item is asserting the waitForMockRequest return value in the E2E fix — cosmetic but materially improves debuggability on timeout.

Comment thread app/test/e2e/specs/mega-flow.spec.ts Outdated
Comment thread app/test/e2e/specs/mega-flow.spec.ts Outdated
Copy link
Copy Markdown
Contributor

@graycyrus graycyrus left a comment

Choose a reason for hiding this comment

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

Clean PR — well done. Moving to approval queue.

This is a solid fix for the cross-workspace persistence race. The approach of threading workspace_dir through the event variants and having subscribers guard against mismatches is exactly right — no new abstractions, minimal allocation cost, and the existing PathBuf identity convention is maintained.

What I verified

Check Result
All 3 publish_global call sites in dispatch.rs thread ctx.workspace_dir
Both affected subscribers (ConversationPersistenceSubscriber, TelegramRemoteSubscriber) have workspace guards
No other handlers match ChannelMessageReceived/ChannelMessageProcessed without the diff updating them
Publisher/subscriber contracts documented in events.rs module docs
11 new tests cover: positive control, stale drop, mid-conversation switch, multiple stale, correct-after-stale
Issue #2602 acceptance criteria (repro gone, regression safety, diff coverage, event contract docs) ✅ All met

CodeRabbit overlap

CodeRabbit flagged the waitForMockRequest silent-timeout issue in the E2E test — that's a valid nit but orthogonal to the core fix. No additional findings from my review.

Nice work threading this through cleanly without over-engineering it. 👍

@coderabbitai coderabbitai Bot added memory Memory store, memory tree, recall, summarization, and embeddings in src/openhuman/memory/. bug labels May 25, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
app/test/e2e/specs/mega-flow.spec.ts (3)

242-242: ⚡ Quick win

Follow the Scenario 1 pattern and add failure diagnostics before Composio RPCs.

The comment at lines 240-241 explains this wait ensures session persistence before Composio RPCs. A timeout here would cause cryptic downstream failures. Capturing the result enables diagnostic logging that would speed debugging.

Refactor to match the established pattern
-    expect(await waitForMockRequest('GET', '/auth/me', 10_000)).toBeDefined();
+    const me = await waitForMockRequest('GET', '/auth/me', 10_000);
+    expect(me).toBeDefined();
+    if (!me) {
+      console.log(`${LOG} Scenario 4: /auth/me timeout before Composio RPCs; recent requests:`, getRequestLog());
+    }

As per coding guidelines: "In E2E specs, assert both UI outcomes and backend/mock effects when relevant. Add failure diagnostics (request logs, dumpAccessibilityTree()) for faster debugging by agents."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/test/e2e/specs/mega-flow.spec.ts` at line 242, Capture the result of
waitForMockRequest('GET', '/auth/me', 10_000) into a variable (e.g., const
authMeReq = await waitForMockRequest(...)) instead of asserting directly, and if
it is undefined or times out, log diagnostic details (mock request logs, the
response body/headers if available) and call dumpAccessibilityTree() before
proceeding to any Composio RPC calls; update the assertion to
expect(authMeReq).toBeDefined() so failures produce those diagnostics and speed
debugging (reference: waitForMockRequest and dumpAccessibilityTree()).

202-202: ⚡ Quick win

Follow the Scenario 1 pattern for consistency and add failure diagnostics.

The inline assertion prevents adding diagnostic output on timeout. Scenario 1 (lines 148-150) demonstrates the preferred pattern: assign the result, assert it's defined, then log. This approach enables conditional diagnostic logging if the wait times out.

Refactor to match the established pattern
-    expect(await waitForMockRequest('GET', '/auth/me', 10_000)).toBeDefined();
+    const me = await waitForMockRequest('GET', '/auth/me', 10_000);
+    expect(me).toBeDefined();
+    if (!me) {
+      console.log(`${LOG} Scenario 3: /auth/me timeout after Gmail login; recent requests:`, getRequestLog());
+    }

As per coding guidelines: "In E2E specs, assert both UI outcomes and backend/mock effects when relevant. Add failure diagnostics (request logs, dumpAccessibilityTree()) for faster debugging by agents."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/test/e2e/specs/mega-flow.spec.ts` at line 202, Replace the inline
assertion that directly expects waitForMockRequest('GET', '/auth/me', 10_000)
with the Scenario 1 pattern: first assign the awaited result of
waitForMockRequest('GET', '/auth/me', 10_000) to a variable (e.g., authRequest),
then assert authRequest is defined, and on the failure branch log diagnostic
info (e.g., request logs and call dumpAccessibilityTree()) to aid debugging;
ensure you reference the waitForMockRequest call and add the conditional
diagnostics after the undefined check so timeouts produce useful output.

569-569: ⚡ Quick win

Follow the Scenario 1 pattern and add failure diagnostics before webhook setup.

The comment at line 568 indicates this wait ensures session persistence before proceeding. Capturing the result enables diagnostic output that would clarify timeout failures in this complex Composio + webhook scenario.

Refactor to match the established pattern
-    expect(await waitForMockRequest('GET', '/auth/me', 10_000)).toBeDefined();
+    const me = await waitForMockRequest('GET', '/auth/me', 10_000);
+    expect(me).toBeDefined();
+    if (!me) {
+      console.log(`${LOG} Scenario 11: /auth/me timeout before Composio+webhook setup; recent requests:`, getRequestLog());
+    }

As per coding guidelines: "In E2E specs, assert both UI outcomes and backend/mock effects when relevant. Add failure diagnostics (request logs, dumpAccessibilityTree()) for faster debugging by agents."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/test/e2e/specs/mega-flow.spec.ts` at line 569, Capture the result of the
waitForMockRequest call (the GET '/auth/me' call) instead of discarding it, then
assert it and emit failure diagnostics before the webhook setup: if the awaited
value is undefined/null or the expect fails, log the returned mock request
object (or its request/response details) and call dumpAccessibilityTree() to
help debug UI state; update the line using waitForMockRequest('GET', '/auth/me',
10_000) to follow the Scenario 1 pattern of storing the result, asserting it
with expect(...).toBeDefined(), and printing/logging the request details and
dumpAccessibilityTree() on failure.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@app/test/e2e/specs/mega-flow.spec.ts`:
- Line 242: Capture the result of waitForMockRequest('GET', '/auth/me', 10_000)
into a variable (e.g., const authMeReq = await waitForMockRequest(...)) instead
of asserting directly, and if it is undefined or times out, log diagnostic
details (mock request logs, the response body/headers if available) and call
dumpAccessibilityTree() before proceeding to any Composio RPC calls; update the
assertion to expect(authMeReq).toBeDefined() so failures produce those
diagnostics and speed debugging (reference: waitForMockRequest and
dumpAccessibilityTree()).
- Line 202: Replace the inline assertion that directly expects
waitForMockRequest('GET', '/auth/me', 10_000) with the Scenario 1 pattern: first
assign the awaited result of waitForMockRequest('GET', '/auth/me', 10_000) to a
variable (e.g., authRequest), then assert authRequest is defined, and on the
failure branch log diagnostic info (e.g., request logs and call
dumpAccessibilityTree()) to aid debugging; ensure you reference the
waitForMockRequest call and add the conditional diagnostics after the undefined
check so timeouts produce useful output.
- Line 569: Capture the result of the waitForMockRequest call (the GET
'/auth/me' call) instead of discarding it, then assert it and emit failure
diagnostics before the webhook setup: if the awaited value is undefined/null or
the expect fails, log the returned mock request object (or its request/response
details) and call dumpAccessibilityTree() to help debug UI state; update the
line using waitForMockRequest('GET', '/auth/me', 10_000) to follow the Scenario
1 pattern of storing the result, asserting it with expect(...).toBeDefined(),
and printing/logging the request details and dumpAccessibilityTree() on failure.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0ccc89ee-f7be-4a9f-a26c-ac3991666bf5

📥 Commits

Reviewing files that changed from the base of the PR and between 897caf9 and 1e3c966.

📒 Files selected for processing (2)
  • .claude/memory.md
  • app/test/e2e/specs/mega-flow.spec.ts
✅ Files skipped from review due to trivial changes (1)
  • .claude/memory.md

coderabbitai[bot]
coderabbitai Bot previously approved these changes May 25, 2026
coderabbitai[bot]
coderabbitai Bot previously approved these changes May 25, 2026
@M3gA-Mind
Copy link
Copy Markdown
Contributor Author

Pre-existing CI failures — not caused by this PR

The two failing checks (test / Rust Core Tests + Quality and Rust Core Coverage (cargo-llvm-cov)) are failing on upstream main right now with the exact same test failures:

  • openhuman::memory::ops::learn::tests::memory_learn_all_uses_all_namespaces_when_none_is_requested
  • openhuman::memory::ops::tool_memory::tests::tool_rules_for_prompt_sorts_by_priority_and_tool_name

See upstream main run 26410626968 for confirmation. This PR does not touch src/openhuman/memory/ops/learn.rs or src/openhuman/memory/ops/tool_memory.rsgit diff upstream/main HEAD -- src/openhuman/memory/ops/ is empty.

@M3gA-Mind M3gA-Mind force-pushed the fix/channel-events-workspace-identity branch from 61e51ee to 68e01f9 Compare May 26, 2026 07:01
M3gA-Mind added 3 commits May 26, 2026 12:35
…event cross-workspace persistence

`ChannelMessageReceived` and `ChannelMessageProcessed` carried no workspace
identity, so `ConversationPersistenceSubscriber` and `TelegramRemoteSubscriber`
would write events into the wrong workspace when login/workspace changed while
events were still in flight.

- Add `workspace_dir: PathBuf` to both `DomainEvent` variants with rustdoc
  describing the publisher/subscriber routing contract
- Populate from `ctx.workspace_dir` at all three publish sites in dispatch.rs
- Add early-return workspace guards in both persistence subscribers; mismatched
  events are silently dropped with a debug log
- Add 11 exhaustive tests covering matching workspace (positive controls),
  stale workspace drops, workspace-switch mid-conversation race, multiple
  stale workspaces, and correct-after-stale ordering

Closes tinyhumansai#2602
…arios

Addresses @coderabbitai: bare await calls could silently time out and
return undefined, letting downstream composio assertions carry the error
in a confusing way. Use expect(...).toBeDefined() so a timeout fails
visibly at the wait site, consistent with the pattern in Scenario 1.
The mock server logs /auth/me on receipt (before the response is sent),
so waitForMockRequest returns while the core is still awaiting the
response. Without a brief pause, composio_list_triggers / composio_enable_trigger
race against auth_store_session finishing and see "no backend session
token". 500ms matches the pattern already used in Scenario 3 for a
similar post-deep-link settle. Also assert /telegram/login-tokens/ wait
in both scenarios so a timeout fails visibly at the wait site.
@M3gA-Mind M3gA-Mind force-pushed the fix/channel-events-workspace-identity branch from 68e01f9 to 81609b4 Compare May 26, 2026 07:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug memory Memory store, memory tree, recall, summarization, and embeddings in src/openhuman/memory/. working A PR that is being worked on by the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Prevent channel conversation events from persisting to the wrong workspace

2 participants