Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: simstudioai/sim
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: main
Choose a base ref
...
head repository: simstudioai/sim
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: fix/gsheets-trashed-empty-guard
Choose a head ref
Checking mergeability… Don’t worry, you can still create the pull request.
  • 3 commits
  • 3 files changed
  • 1 contributor

Commits on Jul 23, 2026

  1. fix(knowledge): purge trashed Google Sheets tabs on a normal sync

    Trashing a spreadsheet made listDocuments return an empty listing,
    but the sync engine's zero-document guard skips deletion
    reconciliation whenever a listing comes back empty and documents
    already exist — it can't tell a genuinely empty source apart from a
    provider outage. For a single-spreadsheet connector, trashing its
    one source item empties the entire listing, so the guard always
    fired and the stale tabs never got cleaned up on a normal sync,
    contradicting the documented behavior.
    
    Add shouldSkipEmptyListing, mirroring shouldReconcileDeletions: a
    connector can now set syncContext.sourceConfirmedEmpty when it has
    positively confirmed the empty result against the source (not
    merely inferred it from an empty listing page), letting
    reconciliation proceed. The Google Sheets connector sets this flag
    when it confirms the spreadsheet is trashed via a direct Drive
    metadata lookup. No other connector sets it, so this doesn't change
    behavior anywhere else.
    waleedlatif1 committed Jul 23, 2026
    Configuration menu
    Copy the full SHA
    c93c12f View commit details
    Browse the repository at this point in the history
  2. fix(knowledge): let sourceConfirmedEmpty also bypass the mass-deletio…

    …n safety threshold
    
    The zero-document guard bypass alone wasn't enough: for a trashed
    spreadsheet with more than 5 tabs, reconciliation would proceed but
    the separate mass-deletion ratio guard (>50% deleted, >5 docs) still
    blocked the actual delete on a normal sync, requiring a forced full
    resync anyway. Extracted the ratio guard into
    exceedsDeletionSafetyThreshold, mirroring shouldSkipEmptyListing, so
    a connector's positive source confirmation bypasses both guards
    consistently.
    waleedlatif1 committed Jul 23, 2026
    Configuration menu
    Copy the full SHA
    147572d View commit details
    Browse the repository at this point in the history
  3. fix(knowledge): replace deletion-safety heuristics with a two-phase t…

    …ombstone
    
    Supersedes the sourceConfirmedEmpty bypass flag with a properly
    general fix, matching how production sync systems (Entra Connect,
    SCIM/Entra ID deprovisioning, Cassandra/Couchbase tombstones) handle
    this exact problem: never let a single observation trigger an
    irreversible mass deletion, no matter how confident the signal looks.
    
    A document missing from a normal sync's listing is now soft-deleted
    (marked pending-removal) rather than hard-deleted immediately. It's
    only actually purged once a *later* sync confirms it's still absent.
    If it reappears in between, it's resurrected automatically — this
    self-heals a transient outage or a bad API response without needing
    to distinguish 'real' emptiness from 'ambiguous' emptiness at all,
    which is what the removed heuristics were trying (and failing) to do
    from a single observation.
    
    This removes shouldSkipEmptyListing, exceedsDeletionSafetyThreshold,
    and sourceConfirmedEmpty entirely — Google Sheets no longer needs a
    connector-specific bypass flag, since a genuinely trashed spreadsheet
    now reconciles through the exact same general path as every other
    connector, with no special-casing and no new misuse surface for
    future connectors. A forced fullSync still purges everything absent
    in one pass, preserving the existing 'trigger a full sync to force
    cleanup' escape hatch.
    
    Uses the existing (previously unused for individual documents)
    document.deletedAt column as the tombstone marker — no schema
    migration required. shouldReconcileDeletions (the isIncremental /
    listingCapped / listingTruncated gate) is unchanged; it still governs
    whether reconciliation may run at all. Resurrection runs
    unconditionally even when that gate is closed, since presence is
    trustworthy evidence regardless of whether the listing was complete.
    waleedlatif1 committed Jul 23, 2026
    Configuration menu
    Copy the full SHA
    f09c6ef View commit details
    Browse the repository at this point in the history
Loading