Skip to content

Sync Policy Infrastructure #784

Description

@malibio

Overview

Implement sync policy infrastructure to control what data is pulled from cloud to local storage and how local changes are pushed to cloud. Sync policies are declarative rules that the sync engine evaluates to determine data transfer behavior.

Architecture Context

This issue is part of the Universal Graph Architecture Transition (Epic #783), specifically Stream D: Sync Infrastructure.

Sync policies follow the same policy node type pattern as lifecycle policies (#755), using policy_type: "sync" to distinguish them.

Key Design Decision: Policies are declarative filters evaluated by the sync engine, not reactive workflows. They answer "what should sync?" continuously.

Problem Statement

With SurrealDB Cloud sync, we need to manage:

  • Local storage limits - Desktop/mobile can't hold entire cloud database
  • Bandwidth efficiency - Don't sync archived/deleted content by default
  • Offline priority - Critical content should sync first
  • User control - Power users may want different sync behavior than casual users

Without sync policies, we either sync everything (bloats local) or nothing old (loses access).

Proposed Solution

1. Sync Policy Schema

{
  "id": "node:<uuid>",
  "node_type": "policy",
  "content": "Default Sync Policy",
  "properties": {
    "policy_type": "sync",
    "enabled": true,
    "priority": 0,
    
    "pull": {
      "lifecycle_states": ["active"],
      "max_age_days": 365,
      "max_storage_mb": 500,
      "node_types": ["*"],
      "priority_order": ["modified_at", "desc"]
    },
    
    "push": {
      "immediate": true,
      "offline_queue_max": 1000
    },
    
    "eviction": {
      "strategy": "lru",
      "trigger_percent": 80,
      "keep_pinned": true
    }
  }
}

2. Pull Strategy Options

Field Purpose Example Values
lifecycle_states Which states to pull ["active"], ["active", "archived"]
max_age_days Rolling window 365, 90, null (no limit)
max_storage_mb Local storage cap 500, 2000
node_types Filter by type ["*"], ["task", "text"]
roots Sync specific subtrees ["node:workspace-1"]
priority_order What syncs first ["modified_at", "desc"]

3. Push Strategy Options

Field Purpose Example Values
immediate Push on every save true, false
batch_interval_seconds Debounce pushes 30, 60
offline_queue_max Max pending changes 1000, 5000

4. Eviction Strategy Options

Field Purpose Example Values
strategy How to choose what to evict "lru", "lifecycle_first", "age_first"
trigger_percent When to start evicting 80 (at 80% capacity)
keep_pinned Never evict pinned nodes true

5. Node Pinning

Users can pin nodes for guaranteed offline access:

UPDATE node:<id> SET properties.pinned = true;

Pinned nodes:

  • Always pulled regardless of sync policy
  • Never evicted
  • Synced with high priority when coming online

6. Default Policies

Profile Pull Policy Use Case
Light Active only, 90 days, 100MB Mobile devices
Standard Active only, 365 days, 500MB Desktop default
Power Active + archived, no age limit, 2GB Offline-heavy users

Acceptance Criteria

Phase 1: Schema & Storage

  • policy schema supports policy_type: "sync"
  • Sync policy nodes can be created/updated/deleted
  • Default sync policy created on first run
  • Pinned property recognized on nodes

Phase 2: Pull Implementation

  • Sync engine reads active sync policies
  • Pull filters by lifecycle state
  • Pull respects max_age_days
  • Pull respects max_storage_mb
  • Pinned nodes always pulled

Phase 3: Push Implementation

  • Push respects immediate vs batched setting
  • Offline queue respects max limit
  • Queue persists across app restarts

Phase 4: Eviction Implementation

  • LRU eviction strategy works
  • Eviction triggers at storage threshold
  • Pinned nodes never evicted
  • Evicted nodes can be re-fetched on demand

Phase 5: Quality

  • Documentation updated
  • Tests cover all sync policy scenarios
  • Code passes bun run quality:fix
  • Tests pass (bun run test:all)

Technical Specifications

Reference Files

  • Architecture: See architecture-target-state.md Section 6
  • Sync engine: TBD (part of SurrealDB Cloud integration)
  • Policy schema: Shared with lifecycle policies

Sync Flow

┌─────────────────────────────────────────────────────────────────┐
│                         CLOUD                                   │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐                      │
│  │  active  │  │ archived │  │ deleted  │                      │
│  │  nodes   │  │  nodes   │  │  nodes   │                      │
│  └────┬─────┘  └────┬─────┘  └────┬─────┘                      │
└───────┼─────────────┼─────────────┼────────────────────────────┘
        │             │             │
        │ Sync Policy │             │
        │ filters     │             │
        ▼             ▼             ▼
   ┌─────────┐   ┌─────────┐   ┌─────────┐
   │  PULL   │   │  MAYBE  │   │  NEVER  │  ← Default policy
   └────┬────┘   └────┬────┘   └─────────┘
        │             │
        ▼             ▼
┌───────────────────────────────────────────┐
│                  LOCAL                     │
│  Eviction policy manages storage          │
└───────────────────────────────────────────┘

Dependencies

Related Issues

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions