Files
agentik/sync-core/build.gradle.kts
T
subochev 92b76c4e3c Добавляет :sync-core — референсная реализация SYNC-SYSTEM.md.
Новый KMP-модуль :sync-core реализует спеку SYNC-SYSTEM.md с нуля, без
опоры на существующие :outbox-api / :journal-api / :client. Цель — собрать
работающую модель «append-only event journal + материализация +
replace-resync», проверить инварианты тестами, и уже потом думать, как это
распределить по существующим абстракциям.

Архитектура (§3-§5 спеки):
  - Cursor(epoch, number) — пара (поколение, счётчик); @JvmInline value
    class; монотонно возрастает внутри эпохи, при wipe/restart эпоха
    меняется и клиент обязан делать replaceState.
  - EventLog / EventLogWriter / EventLogReplica — append-only журнал +
    материализация на стороне клиента (replica ничего не хранит в
    журнале, только state + sync_state + pending).
  - StateStore / Reducer<S, E> — детерминированная свёртка событий в
    снапшот ChatState.
  - PendingEvent + LocalId — offline-write очередь: PENDING → SENT/FAILED.
  - SyncEngine — оркестратор: fetchUpdates → applyRemote → fetchState →
    replaceState → postPending.
  - SyncTransport — четыре endpoint'а (fetchUpdates / fetchState /
    subscribeLive / postPending), сейчас реализован InProcessTransport
    (in-memory), задел под HTTP+WS.

ksqlite-бэкенд (commonMain, ksqlite 0.1.4):
  - SqliteEventLog — append-only с UNIQUE(event_id) для идемпотентности.
  - SqliteEventLogReplica — клиентская сторона (processed_event_id,
    pending_event, sync_state singleton-row).
  - SqliteStateStore — chat_state / message_state + replaceState.
  - SqliteSyncBundle — фабрика для тестов.

CursorExpired split (§6.3 спеки):
  - WRONG_EPOCH — сервер сменил эпоху (wipe/restore/миграция).
  - TOO_OLD — компакция унесла события ниже floor.
Оба → клиент обязан сделать replaceState (sync() делает это сам).

EventLogWriter.beginNewEpoch(newEpoch): Cursor — атомарная смена эпохи
на сервере: DELETE event_log + reset sqlite_sequence + UPDATE
compaction_state, в одной транзакции.

Сборка: jvm + linuxX64 (mingwX64 компилируется, тесты на linux хосте
пропускаются — ksqlite имеет нативные бинарники только под эти три).

Тесты (74, commonTest, проходят на jvm и linuxX64):
  - CursorTest (14) — парсинг, валидация, isAfter/isBefore/compareTo.
  - EpochMismatchTest (6) — WRONG_EPOCH / TOO_OLD → full resync.
  - InvariantsTest — 7 инвариантов спеки на in-memory бэкенде.
  - IdempotencyTest — повторный applyRemote по eventId = no-op.
  - EditDeleteTest — message edit/delete через события.
  - CompactionAndOrderTest — compact сдвигает minAvailableCursor.
  - OfflineWriteTest — pending отправляется при следующем sync().
  - AssistantTest — LocalAssistant возвращает Flow<DomainEvent>.
  - KsqliteSyncSpecTest (15) — все спец-тесты на ksqlite.
  - KsqlitePersistenceTest — file-based persistence.

Существующий код (:outbox-api / :journal-api / :client / :server) не
трогаем — это чистая референсная реализация для последующей миграции.
2026-10-02 01:08:49 +03:00

42 lines
2.0 KiB
Kotlin
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
plugins {
alias(libs.plugins.kotlin.multiplatform)
alias(libs.plugins.kotlin.serialization)
}
// Референсная реализация ТЗ `SYNC-SYSTEM.md` — журнал событий с монотонным
// курсором + материализация (`Chat`/`Message` с `last_seq`), единый протокол
// для клиента и сервера. KMP, всё в commonMain/commonTest где это возможно;
// ksqlite-реализация — в commonMain (ksqlite публикует KMP-варианты для всех
// десктоп-целей), интеграционные тесты под реальной SQLite — в jvmTest.
//
// Цели сборки:
// - commonMain/commonTest содержат pure-Kotlin типы, интерфейсы, in-memory
// реализации и спец-тесты (SyncSpec). Работают на всех 9 KMP-целях.
// - jvmMain + jvmTest дополнительно содержат ksqlite-бэкенд (он же публикуется
// для linuxX64/mingwX64, но запускать с реальной SQLite-схемой удобнее под JVM).
//
// Почему нет iOS/macOS целей: ksqlite не публикует варианты для них. Если
// когда-нибудь понадобится, цели добавляются одной строкой.
kotlin {
jvmToolchain(21)
jvm()
linuxX64()
mingwX64()
sourceSets {
commonMain.dependencies {
implementation(libs.ksqlite)
implementation(libs.kotlinx.serialization.json)
implementation(libs.kotlinx.coroutines.core)
}
commonTest.dependencies {
implementation(kotlin("test"))
implementation(libs.kotlinx.coroutines.test)
// для файлового персистентного теста — KMP-обёртка вокруг fs.
implementation(libs.kotlinx.io.core)
}
}
}