fix(core): sync review round 1: lists, supersede, dedupe conflicts, retries
- dedupe files conflicts for disagreeing fields instead of dropping them - merged-away records never file removals - matched work committed before apply so retries reuse it (no draft leaks) - stale pending events superseded by newer values - multi-source engagement removal only detaches the source - list records applied with history-derived ownership - gone targets resolve as ignored; counts only for committed records Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0604c323c3
commit
a003c3eb7d
8 files changed
+675
-196
No files matched your search
@@ -5,7 +5,7 @@ import type { ConnectionStatus, Database, RunMode } from "@sttracker/db/schema";
|
||||
import type { PluginContext, SourcePlugin, SourceRecord } from "@sttracker/plugin-sdk/types";
|
||||
import { NotFoundError, ValidationError } from "../errors.ts";
|
||||
import type { Actor } from "../history.ts";
|
||||
import { applyRecord, emptyCounts, markRemoved, type RunCounts, type SyncState } from "./apply.ts";
|
||||
import { applyRecord, committed, emptyCounts, markRemoved, type RunCounts, type SyncState } from "./apply.ts";
|
||||
import { ingestListens } from "./listens.ts";
|
||||
|
||||
/** A `source_connections` row with JSON parsed. Credentials stay encrypted; the caller's `makeContext` decrypts. */
|
||||
@@ -92,7 +92,7 @@ export async function runSync(deps: SyncDeps, plugin: SourcePlugin, connectionId
|
||||
.execute();
|
||||
|
||||
const actor: Actor = `plugin:${conn.pluginId}:${conn.id}`;
|
||||
const st: SyncState = { db, userId: conn.userId, connectionId: conn.id, runId, actor, counts: emptyCounts(), log: [] };
|
||||
const st: SyncState = { db, userId: conn.userId, connectionId: conn.id, pluginId: conn.pluginId, runId, actor, counts: emptyCounts(), log: [] };
|
||||
const seen = new Set<string>();
|
||||
const errors: string[] = [];
|
||||
let pullError: string | null = null;
|
||||
@@ -140,7 +140,7 @@ export async function runSync(deps: SyncDeps, plugin: SourcePlugin, connectionId
|
||||
.execute();
|
||||
for (const r of live) {
|
||||
if (seen.has(r.key)) continue;
|
||||
await db.k.transaction().execute((tx) => markRemoved(tx, st, r));
|
||||
await committed(st, (local) => db.k.transaction().execute((tx) => markRemoved(tx, local, r)));
|
||||
}
|
||||
} catch (e) {
|
||||
errors.push(`removal: ${message(e)}`);
|
||||
|
||||
Reference in new issue
Block a user