Skip to content

fix: reconcile orphaned files/entries left by ServiceNow record renames#98

Open
AlexAlvarez092 wants to merge 1 commit into
masterfrom
fix/97-pull-rename-cleanup
Open

fix: reconcile orphaned files/entries left by ServiceNow record renames#98
AlexAlvarez092 wants to merge 1 commit into
masterfrom
fix/97-pull-rename-cleanup

Conversation

@AlexAlvarez092

Copy link
Copy Markdown
Owner

Summary

Fixes a bug where pulling a ServiceNow record that was renamed remotely (e.g. a Script Include's name changed) created a new local file under the new name but left the old file and its sync index entry orphaned, instead of cleaning them up.

Type of change

  • Bug fix
  • New feature
  • Refactor
  • Docs
  • Tests
  • CI / tooling

Related issues

Closes #97

What was changed

  • SnSyncIndexService now detects renames during recordPullFiles, replacePullSnapshot, and replaceTableSnapshot — an incoming pull update matching an existing entry's table/sys_id/fieldName but with a different localPath signals a remote rename.
  • Reconciliation behavior:
    • Old local file unmodified (hash matches baseHash) → deleted, stale index entry removed, user informed via a new PULL_RENAME_CLEANUP_PREFIX message.
    • Old local file has unpushed local edits → left untouched (no data loss), user warned via a new PULL_RENAME_CONFLICT_PREFIX message so the conflict can be resolved manually.
    • Old local file already missing on disk → stale entry silently dropped.
  • Added SnSyncIndexReconciliationResult model and a reportPullRenameReconciliation helper, wired into all four pull commands (pull current, pull by sys_id, pull table, pull all files) so every pull surfaces cleanup/conflict results.
  • Fixed a bug found while testing: recordPullFiles passed state.entries itself as the rename lookup map, so internal bookkeeping deletions incorrectly removed entries from persisted state even in the "keep the old entry" (conflict) case. Now passes a separate shallow copy.
  • Updated developer-docs/sn-pull-*.md (all four pull commands) and docs/commands.md to document the new behavior.
  • Added unit tests for clean rename cleanup, conflict preservation, missing-old-file handling, and delete-failure resilience, plus per-command tests asserting the new messages are surfaced. Coverage remains at 100% (statements, branches, functions, lines).

How to test

  1. Run sn: pullall files to sync a table (e.g. a Script Include).
  2. Open the synced file locally, then rename that same record in ServiceNow (e.g. change its name).
  3. Run sn: pull current on the (now stale) local file, or sn: pull table / sn: pull by sys_id for that record.
  4. Verify: a file is written under the new name, and the old file and its index entry are removed automatically (if unmodified locally). If you'd made local edits to the old file first, verify it is preserved and a conflict warning is shown instead.

Checklist

  • I ran npm run coverage locally.
  • Test coverage is 100% (statements, branches, functions, lines).
  • I updated docs when behavior changed.
  • I did not include secrets, credentials, or tokens.
  • I kept changes focused and backwards-safe (or documented breakage).

Notes for reviewers

  • The rename-cleanup logic never overwrites or discards local edits — if the old file's content doesn't match its last known baseline hash, the old file/entry is preserved and only a warning is shown.
  • pull table / pull all files already have a "clear destination before pull" preference (pull.clearBeforePull); when that preference deletes the destination folder first, this reconciliation naturally has nothing to do (the old file is already gone), so it only matters when the folder isn't cleared before pulling.

When a record's key field (e.g. name) changes remotely, pull commands
previously wrote a file under the new local path but never cleaned up
the old file or its stale index entry, leaving a duplicate behind.

SnSyncIndexService now detects renames (same table/sys_id/fieldName,
different localPath) during recordPullFiles, replacePullSnapshot, and
replaceTableSnapshot, and reconciles them:
- Unmodified old file -> deleted, stale entry dropped, reported via
  PULL_RENAME_CLEANUP_PREFIX.
- Locally modified old file -> left untouched to avoid data loss,
  reported via PULL_RENAME_CONFLICT_PREFIX.
- Missing old file -> stale entry silently dropped.

Wired the new reportPullRenameReconciliation helper into pull current,
pull by sys_id (via snScopedPullCommandService), pull table, and pull
all files, so all four pull commands surface cleanup/conflict results.

Fixed an aliasing bug found while testing: recordPullFiles used
state.entries directly as the rename lookup map, so bookkeeping
deletions during processing incorrectly removed entries from state
even when they should have been preserved (conflict case). Now passes
a shallow copy.

Updated developer-docs/sn-pull-*.md and docs/commands.md to document
the new rename-reconciliation behavior. Added unit tests covering
clean rename cleanup, conflict preservation, missing-file handling,
and delete-failure resilience; coverage remains at 100%.

Closes #97

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: pull commands create duplicate/orphaned files instead of cleaning up renamed records

1 participant