Skip to content

Clarify Event Architecture and Clean Up Misleading Terminology #643

Description

@malibio

Context

This issue started as "Add SSE event ordering tests for browser mode sync" but evolved during implementation when we discovered a critical architectural insight:

NodeSpace already uses explicit event emission from the business logic layer, NOT SurrealDB LIVE SELECT queries.

The LiveQueryService name is misleading because:

  • It does NOT use SurrealDB's LIVE SELECT feature
  • It subscribes to domain events from SurrealStore (explicit business logic events)
  • Events are emitted by application code after CRUD operations, not by database triggers

This explicit event emission approach is actually the correct design for NodeSpace because it provides:

  • Precise control over event timing and content
  • Guaranteed event ordering within transactions
  • No dependency on SurrealDB's LIVE SELECT latency
  • Ability to emit events only for meaningful domain changes

Architectural Decision

Explicit Event Emission vs. LIVE SELECT

Approach Description Status
LIVE SELECT Database automatically emits events for any table change Not used
Explicit Emission Application code emits domain events after operations Current implementation

Why Explicit Emission is Correct for NodeSpace:

  1. Event Ordering: Events are emitted in the correct order by the business logic, not subject to database trigger ordering
  2. Semantic Events: We emit domain-meaningful events (e.g., EdgeRelationship::Hierarchy) not raw table changes
  3. Transaction Boundaries: Events can be emitted at the end of complex operations, not after each intermediate step
  4. Performance: No database polling or trigger overhead
  5. Testability: Events can be easily mocked and verified in tests

The architecture documentation (hierarchy-reactivity-architecture-review.md) has been updated with a warning that clarifies this distinction.

Completed Work

  • Document event ordering guarantees in BrowserSyncService
  • Add tests for SSE event ordering scenarios:
    • Edge created before referenced node exists
    • Node deleted before edge deleted
    • Bulk operations with interleaved events
    • Duplicate edge events (idempotent handling)
    • Concurrent modifications to multiple node trees
  • Verify ReactiveStructureTree handles out-of-order events gracefully
  • Add architecture decision record to hierarchy-reactivity-architecture-review.md
  • Remove unnecessary polling monitor from dev-proxy (cleanup from previous debugging)
  • Confirm event deduplication/batching is NOT needed (defensive measures in stores are sufficient)

Remaining Work

1. Rename LiveQueryService to DomainEventForwarder or EventBridgeService

Acceptance Criteria:

  • Rename file packages/desktop-app/src-tauri/src/services/live_query_service.rs to domain_event_forwarder.rs
  • Update struct name from LiveQueryService to DomainEventForwarder
  • Update all references in mod.rs and lib.rs
  • Update service comments/docs to reflect actual purpose
  • Verify compilation and all tests pass

Why: The current name implies SurrealDB LIVE SELECT queries, which is not what the service does. It forwards domain events from the business logic layer to the Tauri frontend.

2. Update Reactive Store Comments

Acceptance Criteria:

  • Audit packages/desktop-app/src/lib/stores/reactive-structure-tree.svelte.ts for LIVE SELECT references
  • Audit packages/desktop-app/src/lib/services/browser-sync-service.ts for LIVE SELECT references
  • Update comments to reference "domain events" or "explicit events" instead of "LIVE SELECT"
  • Ensure documentation accurately describes the event source

Why: Comments referencing "LIVE SELECT" are misleading for future developers.

3. Audit Transaction Boundaries in Complex Operations

Acceptance Criteria:

  • Review move_node operation to verify single domain event emitted at end
  • Review indent_node and outdent_node for proper event batching
  • Document any operations that emit multiple events (if any)
  • Create follow-up issues if event batching improvements are needed

Why: Complex operations like move_node should emit a single atomic event, not intermediate states.

4. Add Unit Tests for Event Emission Per Operation

Acceptance Criteria:

  • Add test: create_node emits NodeCreated + EdgeCreated events
  • Add test: update_node emits NodeUpdated event
  • Add test: delete_node emits EdgeDeleted + NodeDeleted events (in correct order)
  • Add test: move_node emits appropriate edge events
  • Tests should verify event order and content

Why: Ensures the explicit event emission contract is documented and enforced via tests.

Acceptance Criteria (Overall)

For this issue to be considered complete:

  1. Service renamed with accurate terminology reflecting explicit event emission
  2. All comments and documentation updated to remove LIVE SELECT references
  3. Transaction boundaries audited with findings documented
  4. Unit tests added for event emission per operation
  5. All existing tests continue to pass

Branch Name

Current: feature/issue-643-sse-event-ordering-tests
Suggested: feature/issue-643-event-architecture-cleanup

Related Documentation

  • /docs/architecture/development/hierarchy-reactivity-architecture-review.md - Architecture decision record
  • /packages/core/src/db/events.rs - Domain event definitions
  • /packages/desktop-app/src-tauri/src/services/live_query_service.rs - Service to rename
  • /packages/desktop-app/src/tests/services/browser-sync-service.test.ts - New SSE ordering tests (12 tests)

Technical Notes

Event Flow (Current Implementation):

SurrealStore.create_node()
  → Emits DomainEvent::NodeCreated via broadcast channel
  → LiveQueryService (DomainEventForwarder) receives event
  → Forwards to Tauri frontend via app.emit("node:created", ...)
  → BrowserSyncService receives SSE/Tauri event
  → Updates SharedNodeStore and ReactiveStructureTree

This is NOT:

SurrealDB LIVE SELECT * FROM node
  → Database triggers emit events automatically
  → Events forwarded to frontend

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions