Relationships
↔ sibling #2856#2862 Tests: property test for buildMarkDirtyHook path mapping
Opened by stack72 · 9/30/2026· Shipped 10/1/2026
Background (read this first)
swamp is about to rework its datastore layer. The design proposal is design/enablers/datastore-commit-log.md on the datastore-rework branch. It is not merged; §2 of it is a write-path inventory.
How the datastore works today.
- Repositories write files into the repo's
.swamp/directory, or into the datastore cache dir for a custom datastore. They then call a mark hook,markDirty(relPath?), which reachesDatastoreSyncService(src/domain/datastore/datastore_sync_service.ts, interface at :168, the eight-rulemarkDirtycontract at :199-257). - A caller then flushes, through one of four paths:
acquireModelLocks().flush(src/cli/repo_context.ts:1723);- the global coordinator
flushDatastoreSync(src/cli/mod.ts:2251); pushManagedConfigChanges(src/cli/managed_config_sync.ts:45/153);- serve's
pushChangedToRemote(src/serve/handlers/shared.ts:83-97) under the sync gate.
- The S3 and GCS sync implementations live in swamp-extensions, not here. They own the dirty set, the
.datastore-sync-state.jsonsidecar,_indexshards and_meta.json. - A filesystem datastore has no sync service at all (
repo_context.ts:1170-1178). - Each repo has a SQLite catalog,
.swamp/data/_catalog.db, thatDataQueryServicereads. - Serve runs pollers that pull peers' changes: Config, AccessData, RuntimeData.
What changes. The refactor lands on main in phases:
- Phase 1: a
UnitOfWorkport with a legacy adapter, so repositories stage writes instead of calling the hook directly. - Phase 2: libswamp use cases own the unit of work, and CLI commands and serve stop calling
markDirty/pushChangedthemselves. - Later phases: a new commit-log engine behind an opt-in format.
Phases 1 and 2 must not change any behaviour.
Why this issue exists. Before any of that lands, this repo's own tests have to pin today's behaviour, so a dropped mark, a lost delete or a missed catalog refresh fails a test instead of reaching users. An audit in September 2026 found:
- no in-memory remote to test sync against;
- no test that every file a repository changes gets marked, and several real unmarked paths;
- no two-repo propagation test;
- no ratchet on the write seams Phase 1 will move;
- the sync-service conformance suite only checks method shapes.
This issue is one of a set. The tracking issue is listed under Related. End-to-end CLI tests for the same risks are in swamp-club/swamp-uat #481-#485, #487, #490 and #492.
Rules (from AGENTS.md)
- Unit tests are in-process only: no subprocesses, no process-global mutation; use
withMockedEnv. - Integration tests in
integration/wire real components on a temp filesystem and must not spawn the CLI. - Registry-registered test types use a per-run name built with
crypto.randomUUID(), orinvalidateTypein afinally. - No fixed sleeps (use
waitForfrom@swamp-club/swamp-testing), no wall-clock assertions, andDeno.utimefor mtimes. - Use
@std/pathfor paths andassertPathEqualsfor path comparisons, since tests run on Windows too. - New files need the AGPLv3 header (
deno run license-headers). - Pin today's behaviour, including known gaps. When today's behaviour is a bug, assert it as it is, with a comment naming the bug. Prefer an explicit pinned list checked with
assertPinnedSet, so a later fix forces the test to be updated on purpose. Do not fix production code in these issues unless the issue says so.
Goal
Add a property test for buildMarkDirtyHook's path mapping. Every mark crosses this function, and the refactor keeps it in the legacy adapter.
Current state
buildMarkDirtyHook(src/cli/repo_context.ts:233-252) turns an absolute path into a path relative to the datastore cache, falling back to<repo>/.swamp.- A path outside both sends nothing;
undefinedbecomes a bare mark. - It is wired only in
requireInitializedRepo(:1074) andrequireInitializedRepoUnlocked(:1240), for custom datastores with acachePath. - The only tests are examples at
src/cli/repo_context_test.ts:3424-3470. - There are other property tests, such as
paths_property_test.tsandcomposite_name_property_test.ts, but none for this.
Test
src/cli/repo_context_property_test.ts, using fast-check as the existing *_property_test.ts files do. Properties, over random path segments (including dots, unicode and spaces) under the cache root and under <repo>/.swamp:
- The mark is relative to the cache or
.swamp, uses forward slashes, never starts with.., is never absolute, and contains no backslash, including when the input uses the platform separator. - Mapping is stable: the same input always gives the same mark.
- Any path outside both roots sends no mark, including sibling directories whose names start with the root name (
/cache-otherversus/cache). undefinedgives exactly one bare mark.- For a path under the cache, joining the mark back onto the cache root gives the original absolute path (a round-trip, compared with
assertPathEquals).
Done when
The property test passes on Linux, macOS and Windows path semantics (use @std/path).
Dependencies
Blocked by: nothing, so this can start now
Blocks: nothing
Full dependency graph and waves: swamp-club#2865.
Related
- Tracking issue: swamp-club#2865 (https://swamp-club.com/lab/2865).
Shipped
Click a lifecycle step above to view its details.
Sign in to post a ripple.