Skip to content

Use random commit id when migrating to add morph types#2344

Merged
hahn-kev merged 16 commits into
developfrom
bug/morph-type-seeding-2343
Jun 11, 2026
Merged

Use random commit id when migrating to add morph types#2344
hahn-kev merged 16 commits into
developfrom
bug/morph-type-seeding-2343

Conversation

@hahn-kev

@hahn-kev hahn-kev commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

Fixes #2343

Using deterministic commit IDs during migrations causes problems resulting in commits not ending up in the same order between clients after a sync. This PR changes how we generate commit IDs for the migration which adds morph types, and fixes the CreateMorphTypeChange to be fine with attempting to create an morph type which already exists.

@github-actions github-actions Bot added the 💻 FW Lite issues related to the fw lite application, not miniLcm or crdt related label Jun 9, 2026
@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 4a1e8482-689f-4e1a-86ca-87ba465daf16

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR fixes a regression where projects downloaded from Lexbox fail with commit ID conflicts. The fix separates morphtype seeding into deterministic (project creation) and non-deterministic (migration) paths, updates test infrastructure to support fixed project IDs for regression testing, and adds debug utilities for CRDT project creation.

Changes

Morphtype Seeding Determinism Fix

Layer / File(s) Summary
Morphtype seeding conditional logic
backend/FwLite/LcmCrdt/Objects/PreDefinedData.cs, backend/FwLite/LcmCrdt/CurrentProjectService.cs
AddPredefinedMorphTypes gains isMigration parameter to control seed commit ID generation (random for migrations, deterministic per-project otherwise). Migration now seeds morphtypes only if database is empty.
Project creation and system data seeding refactoring
backend/FwLite/LcmCrdt/CrdtProjectsService.cs, backend/FwLite/LcmCrdt.Tests/MiniLcmApiFixture.cs
Morphtype seeding moves from early CreateProject to SeedSystemData phase with isMigration=false. Test fixture removes manual morphtype seeding and delegates to service layer.
CreateMorphTypeChange migration-aware implementation
backend/FwLite/LcmCrdt/Changes/CreateMorphTypeChange.cs
Inherits from Change<MorphType> instead of CreateChange<MorphType> and overrides ApplyChange as no-op to support replay during migrations.
Test fixture custom project ID support
backend/FwLite/LcmCrdt.Tests/MiniLcmApiFixture.cs
Create and InitializeAsync accept optional projectId to enable deterministic test project identifiers and regression testing.
Regression test for morphtype commit ID correctness
backend/FwLite/LcmCrdt.Tests/Data/DownloadProjectTests.cs, backend/FwLite/LcmCrdt.Tests/Data/RegressionTestHelper.cs
Test uses fixed project GUID targeting v2 regression data, validates downloaded commits match seeded morphtype commits by comparing local/remote row counts and per-index equivalence.

Debug Utilities Enhancement

Layer / File(s) Summary
Debug utilities and JSON sync initialization
backend/FwLite/LcmDebugger/FakeSyncSource.cs, backend/FwLite/LcmDebugger/Utils.cs
FakeSyncSource.FromJsonFile lazily initializes CRDT JSON serialization when no options provided. New NewProjectFromSyncable extension creates and syncs CRDT projects with optional project ID.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • sillsdev/languageforge-lexbox#2277: Both PRs modify the morph-type seeding path in CurrentProjectService.MigrateDb and PreDefinedData.AddPredefinedMorphTypes to address commit ID correctness around predefined morphtypes.
  • sillsdev/languageforge-lexbox#2278: Both PRs refactor predefined morphtype seeding across PreDefinedData, MiniLcmApiFixture, CrdtProjectsService, and CurrentProjectService, changing how per-project seed commit GUIDs are generated and passed.

Suggested labels

💻 FW Lite

Suggested reviewers

  • myieye

Poem

🐰 Commits once clashed with morphtypes seeded,
Random IDs where determinism was needed,
Now migration and creation go their own ways,
With project-locked GUIDs through all of the days,
Downloaded projects will sync without strife! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: converting morph type migrations to use random commit IDs instead of deterministic ones.
Description check ✅ Passed The description clearly relates to the changeset, explaining the problem and the solution of using random commit IDs and making CreateMorphTypeChange idempotent.
Linked Issues check ✅ Passed The PR successfully addresses issue #2343 by using random commit IDs for morph type migrations, making CreateMorphTypeChange idempotent, and conditionally seeding morph types to avoid conflicts between client downloads.
Out of Scope Changes check ✅ Passed All changes are scoped to the morph type seeding issue: modifying how commit IDs are generated during migrations, making CreateMorphTypeChange handle existing entries, adjusting test fixtures, and updating related service initialization logic.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch bug/morph-type-seeding-2343

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

C# FwHeadless Unit Tests

48 tests   48 ✅  17s ⏱️
 5 suites   0 💤
 1 files     0 ❌

Results for commit 8de8c07.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

UI unit Tests

  1 files   62 suites   30s ⏱️
186 tests 186 ✅ 0 💤 0 ❌
258 runs  258 ✅ 0 💤 0 ❌

Results for commit 8de8c07.

♻️ This comment has been updated with latest results.

@argos-ci

argos-ci Bot commented Jun 9, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Argos notifications ↗︎

Build Status Details Updated (UTC)
default (Inspect) ✅ No changes detected - Jun 11, 2026, 2:42 AM

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/FwLite/LcmCrdt.Tests/Data/DownloadProjectTests.cs`:
- Around line 12-13: The test currently syncs remote state into an empty local
DB because MiniLcmApiFixture.InitializeAsync() no longer seeds morph types;
update the test to seed the local side before calling SyncWith(remoteModel) by
invoking the same creation/download path the app uses or explicitly creating the
deterministic morph-type seed commit on the fixture (e.g., call the project
creation/download helper or a new
MiniLcmApiFixture.SeedDeterministicMorphTypes()/CreateDeterministicMorphTypeSeedCommit()
helper) so the local project contains the deterministic seed commit prior to
synchronization.

In `@backend/FwLite/LcmCrdt.Tests/Data/RegressionTestHelper.cs`:
- Around line 41-42: The helper currently calls
projectsService.SetupProjectContext(crdtProject) reusing the same Project.DbPath
so CurrentProjectService's static MigrationTasks (keyed by Project.DbPath) skips
migrations; fix by ensuring each test initialization uses a unique sqlite path
or clears the memoized entry before setup: either generate a unique db file name
for crdtProject (e.g., append a GUID/timestamp) so SetupProjectContext runs
migrations/seeding against a fresh path, or explicitly remove the MigrationTasks
entry keyed by crdtProject.DbPath from CurrentProjectService before calling
SetupProjectContext so migrations are not skipped.

In `@backend/FwLite/LcmDebugger/FakeSyncSource.cs`:
- Line 53: The File.OpenRead(path) stream passed into JsonSerializer.Deserialize
in FakeSyncSource.cs is never disposed (variable changes), which can leak file
handles; fix by creating and disposing the stream explicitly (e.g., using/using
var for the File.OpenRead(path) stream) before calling
JsonSerializer.Deserialize, or alternatively read the file into a string with
File.ReadAllText and deserialize that, ensuring the stream is closed; update the
code around the changes assignment in the FakeSyncSource class to use one of
these approaches.

In `@backend/FwLite/LcmDebugger/Utils.cs`:
- Around line 55-56: The code returns crdtMiniLcmApi even when
DataModel.SyncWith may fail; update the caller to verify sync success before
returning by either awaiting SyncWith and checking its boolean/result (if it
returns a status) or wrapping the await in a try/catch and rethrowing or
returning a failure indicator when sync fails; specifically modify the block
that calls services.GetRequiredService<DataModel>().SyncWith(syncable) so that
DataModel.SyncWith failures are detected and handled (e.g., throw a descriptive
InvalidOperationException or return null/error) and only return crdtMiniLcmApi
when the sync completed successfully.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 9b3d23df-6ea7-4a46-8a8c-5af05f4d7b58

📥 Commits

Reviewing files that changed from the base of the PR and between bdbfc30 and 945d2b8.

📒 Files selected for processing (9)
  • backend/FwLite/LcmCrdt.Tests/Data/DownloadProjectTests.cs
  • backend/FwLite/LcmCrdt.Tests/Data/RegressionTestHelper.cs
  • backend/FwLite/LcmCrdt.Tests/MiniLcmApiFixture.cs
  • backend/FwLite/LcmCrdt/Changes/CreateMorphTypeChange.cs
  • backend/FwLite/LcmCrdt/CrdtProjectsService.cs
  • backend/FwLite/LcmCrdt/CurrentProjectService.cs
  • backend/FwLite/LcmCrdt/Objects/PreDefinedData.cs
  • backend/FwLite/LcmDebugger/FakeSyncSource.cs
  • backend/FwLite/LcmDebugger/Utils.cs

Comment thread backend/FwLite/LcmCrdt.Tests/Data/DownloadProjectTests.cs
Comment thread backend/FwLite/LcmCrdt.Tests/Data/RegressionTestHelper.cs Outdated
Comment thread backend/FwLite/LcmDebugger/FakeSyncSource.cs Outdated
Comment thread backend/FwLite/LcmDebugger/Utils.cs Outdated
Comment thread backend/FwLite/LcmCrdt/Changes/CreateMorphTypeChange.cs Outdated
Comment thread backend/FwLite/LcmCrdt/CurrentProjectService.cs
@myieye myieye force-pushed the bug/morph-type-seeding-2343 branch from b334094 to d4db943 Compare June 10, 2026 11:54
@myieye

myieye commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator

I thought this PR would start actually just importing morph-types from fwdata, but I confused some of our fwheadless import code with our client-side "import local FieldWorks classic project" code. It would be non-trivial to stop seeding the predefined morph-types commit in fw-headless, because fw-headless uses our standard "open/migrate project" code. I think we should leave that until we pull out the morph-types data migration. Then we could/should easily standardize the morph-type import code to use the same pattern as other entities (instead of MorphTypes.Sync).

I've created the follow up clean-up issue: #2350 and added code comments referencing that issue.

@hahn-kev hahn-kev merged commit 3235bd4 into develop Jun 11, 2026
20 checks passed
@hahn-kev hahn-kev deleted the bug/morph-type-seeding-2343 branch June 11, 2026 03:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

💻 FW Lite issues related to the fw lite application, not miniLcm or crdt related

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Downloading some projects results in System.NotSupportedException: type JsonPatchChange`1 does not support NewEntity

2 participants