refactor(sync): reduce MAX_VECTOR_CLOCK_SIZE from 30 to 20

Lower the cap to leave headroom for future increases and surface
size-related edge cases earlier. All pruning logic is MAX-agnostic
so this is a safe constant change with documentation updates.
This commit is contained in:
Johannes Millan 2026-02-12 13:42:32 +01:00
parent 53769019e2
commit f37280e082
12 changed files with 21 additions and 21 deletions

View file

@ -126,7 +126,7 @@ The app uses NgRx (Redux pattern) for state management. Key state slices:
10. **TODAY_TAG is a Virtual Tag**: TODAY_TAG (ID: `'TODAY'`) must **NEVER** be added to `task.tagIds`. It's a "virtual tag" where membership is determined by `task.dueDay`, and `TODAY_TAG.taskIds` only stores ordering. This keeps move operations uniform across all tags. See `docs/ai/today-tag-architecture.md`.
11. **Event Loop Yield After Bulk Dispatches**: When applying many operations to NgRx in rapid succession (e.g., during sync replay), add `await new Promise(resolve => setTimeout(resolve, 0))` after the dispatch loop. `store.dispatch()` is non-blocking and returns immediately. Without yielding, 50+ rapid dispatches can overwhelm the store and cause state updates to be lost. See `OperationApplierService.applyOperations()` for the reference implementation.
12. **SYNC_IMPORT Semantics**: `SYNC_IMPORT` (and `BACKUP_IMPORT`) operations represent a **complete fresh start** - they replace the entire application state. All operations without knowledge of the import (CONCURRENT or LESS_THAN by vector clock) are dropped for all clients. See `SyncImportFilterService.filterOpsInvalidatedBySyncImport()`. This is correct behavior: the import is an explicit user action to restore to a specific state, and concurrent work is intentionally discarded.
13. **Vector Clock Pruning**: `MAX_VECTOR_CLOCK_SIZE` is 30 (a 30-entry clock is ~500 bytes). Pruning is extremely rare (needs 31+ unique client IDs). The server MUST prune (`limitVectorClockSize`) **after** conflict detection but **before** storage — never before comparison. The server's `sanitizeVectorClock()` applies a DoS cap at `5x MAX_VECTOR_CLOCK_SIZE` (150 entries) but does NOT prune to MAX. See `docs/sync-and-op-log/vector-clocks.md`.
13. **Vector Clock Pruning**: `MAX_VECTOR_CLOCK_SIZE` is 20 (a 20-entry clock is ~333 bytes). Pruning is extremely rare (needs 21+ unique client IDs). The server MUST prune (`limitVectorClockSize`) **after** conflict detection but **before** storage — never before comparison. The server's `sanitizeVectorClock()` applies a DoS cap at `5x MAX_VECTOR_CLOCK_SIZE` (100 entries) but does NOT prune to MAX. See `docs/sync-and-op-log/vector-clocks.md`.
## Git Commit Messages