GeoLeaf Core API - v3.19.0
    Preparing search index...

    Interface ConflictRecord

    One settled conflict — keyed [layerId, localId], one record per entity.

    🛑 WHY THE STORE EXISTS. lastWriteWins is the policy, and it was made OBSERVABLE on 17/09/2026 — detected, logged, then settled by an unfiltered re-send. What no part of the cycle did was LOOK at the row it was about to crush. After an overwritten update the server still holds a row; after an overwritten delete it holds nothing, and neither did anything else: that is the only irrecoverable loss of the whole write cycle.

    🛑 THE KEY IS THE BOUND, and it is derived rather than invented. db/eviction.ts knows a single store name (layers), so this store is UNREACHABLE by eviction exactly as features is — nothing will ever purge it. Keying by entity caps it at one row per entity, so its size is bounded by the layer it describes. A journal would have needed a ceiling, and a ceiling here would be a number posted in the noise band — something this repository has paid for twice. The cost is stated rather than hidden: an entity that conflicts twice keeps only the most recently crushed version.

    ⚠️ It carries no zone index, and no index at all (decision of 17/09/2026). Reading a layer costs 0,45 to 0,8 s at 30 000 entities from disk, which does not justify one, and the composite key already yields per-layer traversal by key range — IDBKeyRange.bound([layerId], [layerId, []]), the reasoning db/features.ts carries in full.

    ⚠️ The server's row is EVIDENCE, never a source. Nothing writes it back into features: doing so would overwrite what the operator captured, which is the sixth defect closed on 17/09/2026 reappearing in a new place.

    interface ConflictRecord {
        layerId: string;
        localId: string;
        serverId: string | null;
        kind: SyncOperationKind;
        entryId: string;
        detectedAt: number;
        baseVersion: VersionMarker | null;
        serverVersion: VersionMarker | null;
        serverFeature: Record<string, unknown> | null;
        readOutcome: ConflictReadOutcome;
        settledBy: "lastWriteWins";
        profileId?: string;
    }
    Index
    layerId: string
    localId: string
    serverId: string | null

    The row's server identity, when the record had one.

    The operation that met the conflict.

    entryId: string

    The queue entry it came from — the handle a report needs to name the capture.

    detectedAt: number

    When the conflict was settled, milliseconds since epoch.

    baseVersion: VersionMarker | null

    The marker the local edit was based on — the filter that matched nothing.

    serverVersion: VersionMarker | null

    The marker the crushed row carried. null unless readOutcome is "read".

    serverFeature: Record<string, unknown> | null

    The crushed row, as the server returned it. null unless readOutcome is "read".

    ⚠️ Stored as the server's own shape, not as a GeoJSON Feature: converting it would mean guessing which column is the geometry on a row nothing will ever re-send. What is kept is what was there.

    readOutcome: ConflictReadOutcome

    What the re-read could establish — see ConflictReadOutcome.

    settledBy: "lastWriteWins"

    How it was settled.

    A single value today, and declared rather than implied for the reason ConflictPolicy gives: the record must say which policy produced it, or a later policy would make every archived record ambiguous.

    profileId?: string

    The profile the conflicting write was queued under — its OutboxEntry.profileId. The store is shared by every profile of the origin: a conflict is listed, and purged, under its own profile. Absent on a conflict archived before 3.18.0, or for a write queued before then, which every profile reads, as before.