Skip to content

test(e2e): isolate and streamline two-client sync scenarios - #146

Merged
ClaudiaFang merged 2 commits into
claude/source-control-foundationfrom
claude/e2e-two-client-scope
Aug 31, 2026
Merged

ClaudiaFang merged 2 commits into
claude/source-control-foundationfrom
claude/e2e-two-client-scope

Conversation

@ClaudiaFang

@ClaudiaFang ClaudiaFang commented Aug 31, 2026 •

Copy link
Copy Markdown
Member

Summary

Two rounds on this PR, per review feedback:

Round 1 — scope isolation

  • TwoClient's refresh() bypassed vault-folder filtering entirely and the fixture left rootPath/vaultFolder empty, so every refresh() classified the whole shared branch's remote tree, not just this run's e2e-tc-<runId>/ namespace.
  • Scoped both sides through the real production rootPath/vaultFolder model: createSyncManagerFixture({ scoped: true }) configures the git service's own rootPath and settings.vaultFolder to the same e2e-tc-<runId> value, so the vaultFolder-strip / rootPath-readd round trip cancels out symmetrically (push/pull targets unchanged, remote-tree classification now actually scoped).
  • Added a fail-fast scope-leakage assertion after every refresh(), and opt-in timing diagnostics (E2E_TIMING_DEBUG=1).

Round 2 — streamline

  • Extracted the vaultFolder path-mapping rules into a pure shared module src/logic/sync/vault-folder-scope.ts, used by src/main.ts, SyncScanner.toRepoPath (both now delegate, behavior unchanged), and the E2E TwoClient wiring — production and the E2E fixture can no longer silently drift apart on this logic.
  • P0-1: removed a redundant second baseline that was silently testing modify instead of the intended create.
  • P0-2: removed its trailing expectIdempotent + second convergence check — already fully covered by P0-1's own idempotency assertion; P0-2's real contract (concurrent edits on different files both survive) was already proven without it.
  • convergence-assertions.ts: added captureRemoteSnapshot so expectConverged/expectMetadataConsistent share one getFile-per-path + one listFiles instead of each independently re-fetching the same remote files.

Explicitly not done: no E2E_TEST_TIMEOUT_MS/retry changes, no GitLab-provider-side server-side rootPath listing optimization, no production sync semantics changes (the main.ts/SyncScanner.ts edits are a pure logic-preserving extraction).

Test plan

  • npx eslint . — 0 errors (1 pre-existing unrelated warning)
  • npm run build (tsc + Obsidian 1.11.0 compat typecheck + esbuild) — passed
  • npx vitest run — 68 files / 862 tests passed
  • scripts/run-e2e.sh --provider gitlab (and github/gitea) against a real provisioned branch/CI — not run in this environment (no Docker daemon / provider credentials here); needed to confirm P0-1..P0-5 land in the target ranges and GitLab stops hitting 120s in practice.

🤖 Generated with Claude Code

https://claude.ai/code/session_01SNTkwXym3gvHDn8rhhSPap

ClaudiaFang and others added 2 commits August 31, 2026 16:43
TwoClient's refresh() bypassed vault-folder filtering entirely
(filterFilesByVaultFolder/filterPathByVaultFolder were no-ops) and the
fixture left rootPath/vaultFolder empty, so every refresh() classified
the WHOLE shared branch's remote tree, not just this run's
e2e-tc-<runId>/ namespace. Other suites' leftover fixtures inflated
tree-listing/refresh time and risked the 120s per-test timeout.

Scope both sides via the real production rootPath/vaultFolder model
instead of a test-only filter: createSyncManagerFixture({ scoped: true })
configures the git service's own rootPath (env.ts contexts now accept
one) and settings.vaultFolder to the same e2e-tc-<runId> value, so the
vaultFolder-strip / rootPath-readd round trip cancels out and push/pull
targets stay unchanged while remote-tree classification is actually
scoped. TwoClient's refresh/filter wiring now mirrors main.ts's real
filterFilesByVaultFolder/filterPathByVaultFolder/getNormalizedPath/
getVaultPath instead of bypassing them.

Also adds a fail-fast scope-leakage assertion after every refresh() and
opt-in timing diagnostics (E2E_TIMING_DEBUG=1) around refresh/sync/
baseline, so a future regression or slow run is attributable instead of
surfacing only as a suite timeout.

E2E fixture/support/diagnostics only — no changes to E2E_TEST_TIMEOUT_MS,
retry policy, or production sync code.

npx eslint . — 0 errors (1 pre-existing unrelated warning)
npm run build — passed
npx vitest run — 68 files / 862 tests passed

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SNTkwXym3gvHDn8rhhSPap
Follow-up to the scope-isolation commit, per review feedback:

- Extracted the vaultFolder path-mapping rules (filterPathByVaultFolder/
  filterFilesByVaultFolder/getNormalizedVaultPath/
  getVaultPathFromNormalized) into a pure module
  src/logic/sync/vault-folder-scope.ts, shared by src/main.ts,
  SyncScanner.toRepoPath (both now delegate, behavior unchanged), and
  the E2E TwoClient wiring (now imports the same functions instead of a
  hand-copied duplicate) — production and the E2E fixture can no longer
  silently drift apart on this logic.
- P0-1: removed the redundant second baseline (`other` was baselined
  then immediately treated as "A creates a new file", which was really
  exercising modify, not create); `other` is now a genuine create, one
  fewer real provider push + verifier read.
- P0-2: removed its trailing expectIdempotent + second
  expectTwoClientConvergence — idempotency-under-repeated-sync is
  already covered by P0-1's own expectIdempotent; P0-2's actual contract
  (concurrent edits on different files both survive) is already proven
  by the first convergence check + explicit remote-content assertions.
- convergence-assertions.ts: added captureRemoteSnapshot/RemoteSnapshot
  so expectConverged/expectMetadataConsistent share one getFile-per-path
  + one listFiles instead of each independently re-fetching the same
  remote files; expectTwoClientConvergence now captures once and passes
  it to both.
- Wrapped captureRemoteSnapshot in the existing opt-in timed() helper as
  "remote snapshot (verifier)" for the same E2E_TIMING_DEBUG=1 breakdown.

Not done this round (per plan): no GitLab server-side rootPath listing
optimization, no timeout/retry changes, no production sync semantics
changes — the main.ts/SyncScanner.ts edits are a pure logic-preserving
extraction only.

npx eslint . — 0 errors (1 pre-existing unrelated warning)
npm run build — passed
npx vitest run — 68 files / 862 tests passed

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SNTkwXym3gvHDn8rhhSPap
@ClaudiaFang ClaudiaFang changed the title test(e2e): isolate two-client sync scope test(e2e): isolate and streamline two-client sync scenarios Aug 31, 2026
@sonarqubecloud

Copy link
Copy Markdown

@ClaudiaFang
ClaudiaFang marked this pull request as ready for review August 31, 2026 09:47
@ClaudiaFang
ClaudiaFang merged commit 5422666 into claude/source-control-foundation Aug 31, 2026
12 checks passed
@ClaudiaFang
ClaudiaFang deleted the claude/e2e-two-client-scope branch August 31, 2026 09:47
@ClaudiaFang

Copy link
Copy Markdown
Member Author

🎉 This PR is included in version 1.6.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant