- This is a Swift Package for Core Data persistent history tracking.
- The main target is
PersistentHistoryTrackingKit. - Tests use Swift Testing and heavily exercise Core Data, SQLite-backed stores, background contexts, and persistent history.
- Prefer small, targeted changes.
- Keep Swift 6 concurrency rules in mind.
- Avoid changing test timing or adding arbitrary sleeps unless there is a reproducible failure that requires it.
- Do not assume flaky behavior is code-related until build cache, Xcode test settings, and toolchain state are ruled out.
- Do not run
git commitandgit pushin parallel. Always wait for the commit to finish before pushing.
- Command-line full test runs should use parallel execution:
swift test --parallel- or
./test.sh
./test.shis the preferred full-suite command because it enables Core Data concurrency assertions viacom.apple.CoreData.ConcurrencyDebug=1.- When debugging failures, prefer running a single test file or a filtered suite first.
- Swift Testing parallel runs should be treated as same-process concurrency, not process isolation per test case.
- Do not assume
staticstate is isolated per test. Static helpers in the test target are shared across concurrently running suites. - For new Core Data tests, do not write directly through
viewContextor a raw background context from the test body. - Prefer
Tests/PersistentHistoryTrackingKitTests/TestAppDataHandler.swiftand actor-isolated helper methods for creating, updating, deleting, and reading test data. - If a test needs direct inspection of a handler-owned context, use the handler's
withContextAPI rather thancontext.performfrom the test body. - Prefer real test data and the actual transaction-processing path over synthetic Core Data artifacts. Do not hand-build
HookContext,NSManagedObjectID, or similar fake inputs when a test can create data throughTestAppDataHandlerand trigger processing through the library.
- Full-suite parallel execution has been revalidated after test-infrastructure fixes.
- Repeated parallel runs have been observed to pass after serializing test container creation.
- Repeated Xcode runs of
cleanTransactionsByTimestampAndAuthorshave been observed to pass. TestModelBuilder.createContaineris intentionally serialized with a global lock.- Reason: concurrent
NSPersistentContainercreation andloadPersistentStorescan crash inside Core Data withEXC_BAD_ACCESS, even when each test uses a unique SQLite store URL. - The container creation lock is required for test stability; do not remove it unless the Core Data initialization path is reworked and revalidated under repeated parallel runs.
If a crash or hang appears again, collect the following before changing code:
- The exact test name or suite name
- Whether the run was serial or parallel
- Whether the run happened in Xcode or from the command line
- The crash stack, exception type, or final console output
- Whether
.buildor Xcode DerivedData had just been reused after a toolchain/Xcode change
- If SwiftPM reports compiler/module version mismatches, clear
.buildand rerun. - If Xcode behaves inconsistently while command-line parallel runs are stable, suspect DerivedData or Xcode test execution settings before changing repository code.
- Git tags for releases should use the format
x.x.x. - Examples:
1.0.02.1.3
Sources/PersistentHistoryTrackingKit/PersistentHistoryTrackingKit.swiftSources/PersistentHistoryTrackingKit/TransactionProcessorActor.swiftSources/PersistentHistoryTrackingKit/TransactionTimestampManager.swiftTests/PersistentHistoryTrackingKitTests/TestModels.swifttest.sh