Skip to content

Update SIL.Harmony to rc.234 and rename CrdtConfig to HarmonyConfig - #2482

Open
hahn-kev-bot wants to merge 7 commits into
developfrom
update-harmony-rc234
Open

Update SIL.Harmony to rc.234 and rename CrdtConfig to HarmonyConfig#2482
hahn-kev-bot wants to merge 7 commits into
developfrom
update-harmony-rc234

Conversation

@hahn-kev-bot

@hahn-kev-bot hahn-kev-bot commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Update harmony to the latest version and use the new APIs for getting types.


AI summary

Updates SIL.Harmony 0.2.1-rc.225rc.234 and adapts LexBox to the renamed/reworked config API. Uses the released package only — none of the unreleased reduce-sync-work projection changes.

Harmony API changes handled

  • CrdtConfig was renamed to SIL.Harmony.Config.HarmonyConfig. Renamed all references (types, variables, fields, doc comments) and added the using SIL.Harmony.Config; import. The unrelated LcmCrdtConfig type is untouched.
  • The ChangeTypeListBuilder now freezes the first time its JSON options are built, so ConfigureCrdt no longer reads JsonSerializerOptions mid-configuration (that threw "ChangeTypeListBuilder is frozen" before AddRemoteResourceEntity). The ExampleSentence translation modifier is attached via the new deferred HarmonyConfig.ConfigureJsonOptions hook instead.
  • HarmonyConfig.ChangeTypes now yields RegisteredChangeType descriptors. Added LcmCrdtKernel.AllRegisteredChanges(); AllChangeTypes() projects .Type off it.
  • IChange polymorphism moved out of the type-info resolver into an internal JsonConverter Harmony only adds to its own options. Added MakeLcmCrdtExternalJsonOptions(), which copies Harmony's converters onto the Web-cased sync options used by the Refit client. Without it, decoding a server changes response throws "Deserialization of interface or abstract types is not supported. Type 'SIL.Harmony.Changes.IChange'".

Cleanups

  • ChangeTypesCodeGenerator and HistoryService.ListActivityChangeTypes now use the authoritative RegisteredChangeType.Discriminator instead of re-deriving the $type; removed the now-unused HistoryService.GetChangeTypeKeyFromType.

Generated TypeScript is unchanged (discriminators identical).

Test plan

  • Builds against rc.234: FwLiteOnly.slnf, FwHeadless, LexBoxApi, Testing, FwLiteMaui
  • LcmCrdt.Tests config / serialization / entity-copy suites pass (86 passed, 1 skipped)
  • Broader CRDT sync round-trips (FwLiteProjectSync.Tests) — recommend confirming in CI

hahn-kev and others added 3 commits July 24, 2026 09:01
The new Harmony release renames CrdtConfig to SIL.Harmony.Config.HarmonyConfig
and changes several APIs. This adapts LexBox to compile and run against it:

- Add a `global using CrdtConfig = SIL.Harmony.Config.HarmonyConfig;` shim to
  each project that references CrdtConfig, so existing references keep compiling
  (transitional; a full rename can follow).
- ConfigureCrdt no longer reads config.JsonSerializerOptions directly — Harmony
  now freezes the ChangeTypeListBuilder the first time the options are built,
  which threw "ChangeTypeListBuilder is frozen" before AddRemoteResourceEntity.
  Attach the ExampleSentence translation modifier via the new deferred
  config.ConfigureJsonOptions hook instead.
- ChangeTypes now yields RegisteredChangeType descriptors; project to .Type in
  AllChangeTypes and ConfigRegistrationTests.
- IChange polymorphism moved out of the type-info resolver into an internal
  JsonConverter Harmony only adds to its own JsonSerializerOptions. Add
  MakeLcmCrdtExternalJsonOptions, which copies those converters onto the
  Web-cased sync options, and use it for the Refit client. Without it, decoding
  a server changes response threw "Deserialization of interface or abstract
  types is not supported. Type 'SIL.Harmony.Changes.IChange'".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…lists

- Add LcmCrdtKernel.AllRegisteredChanges() returning Harmony's RegisteredChangeType
  descriptors directly; AllChangeTypes() now just projects .Type off it.
- ChangeTypesCodeGenerator and HistoryService.ListActivityChangeTypes now read the
  authoritative $type discriminator from RegisteredChangeType.Discriminator instead
  of re-deriving it, so the generated list and activity keys can't drift from what
  the serializer actually writes.
- Remove HistoryService.GetChangeTypeKeyFromType, which existed only to share that
  now-unnecessary derivation. Generated TS is unchanged (discriminators identical).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the transitional `global using CrdtConfig = HarmonyConfig` shims with the
real rename now that we build against the renamed SIL.Harmony type:

- Rename every CrdtConfig type reference to HarmonyConfig and add the
  `using SIL.Harmony.Config;` import the alias was masking.
- Rename the corresponding `crdtConfig` variables/parameters/fields (and their
  doc comments) to `harmonyConfig`. LcmCrdtConfig — an unrelated local type — is
  left untouched, including WebTroubleshootingService's `crdtConfig` which holds
  an LcmCrdtConfig.
- Delete the nine HarmonyConfigAlias.cs shim files.

Purely mechanical; no behavior change. Generated TypeScript is unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

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 Plus

Run ID: f771a26b-78af-4a1b-9671-8ab0720fd9a0

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

Changes

The PR updates Harmony package versions, replaces FwLite’s CrdtConfig usage with HarmonyConfig across service wiring and JSON handling, adds registered-change enumeration, updates change-type consumers, and aligns tests and harnesses with the new configuration shape.

HarmonyConfig migration

Layer / File(s) Summary
Configuration and serialization core
backend/Directory.Packages.props, backend/FwLite/LcmCrdt/LcmCrdtKernel.cs, backend/FwLite/LcmCrdt/Json.cs
Package versions advance to 0.2.1-rc.234; kernel configuration, JSON options, and registered change enumeration use HarmonyConfig.
Service and runtime integration
backend/FwLite/FwLite*/..., backend/FwLite/LcmCrdt/..., backend/FwLite/LcmDebugger/FakeSyncSource.cs
Application services, database contexts, media and snapshot services, and runtime helpers resolve HarmonyConfig options.
Registered change consumers
backend/FwLite/FwLiteShared/TypeGen/ChangeTypesCodeGenerator.cs, backend/FwLite/LcmCrdt/HistoryService.cs
Generated change types and activity listings use registered discriminators directly.
Test configuration updates
backend/FwLite/LcmCrdt.Tests/..., backend/Testing/FwHeadless/Services/SyncWorkerTestHarness.cs
Tests and service harnesses construct or resolve HarmonyConfig and adapt registered-change assertions.
Estimated code review effort: 3 (Moderate) ~25 minutes

Possibly related PRs

Suggested reviewers: myieye

Poem

A rabbit hops through configs bright,
Harmony guides the JSON right.
Change types bloom in fields of code,
Tests carry carrots down the road.
Version bells ring—rc.234!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 9.38% 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 clearly matches the main change: updating SIL.Harmony and renaming CrdtConfig to HarmonyConfig.
Description check ✅ Passed The description is directly related to the changeset and accurately summarizes the package update and API rename.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch update-harmony-rc234

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.

@github-actions github-actions Bot added 💻 FW Lite issues related to the fw lite application, not miniLcm or crdt related 📦 Lexbox issues related to any server side code, fw-headless included labels Jul 24, 2026
@argos-ci

argos-ci Bot commented Jul 24, 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 - Jul 24, 2026, 6:19 AM
e2e (Inspect) ✅ No changes detected - Jul 24, 2026, 6:28 AM

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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/FwLiteWeb/FwLiteWebKernel.cs`:
- Around line 33-35: The web and debugger sync JSON configuration only copies
Harmony’s type resolver, omitting its converters needed for IChange
polymorphism. Update the JsonOptions configuration in FwLiteWebKernel.cs and the
web-options setup in FakeSyncSource.cs to reuse MakeLcmCrdtExternalJsonOptions()
or copy its JsonSerializerOptions.Converters, and add web/debugger coverage for
a sync payload containing ChangeEntity<IChange>.
🪄 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 Plus

Run ID: 30347e29-b886-440e-88a7-b68949850979

📥 Commits

Reviewing files that changed from the base of the PR and between c15d806 and 1333113.

📒 Files selected for processing (24)
  • backend/Directory.Packages.props
  • backend/FwLite/FwLiteMaui/FwLiteMauiKernel.cs
  • backend/FwLite/FwLiteProjectSync/ProjectSnapshotService.cs
  • backend/FwLite/FwLiteShared/FwLiteSharedKernel.cs
  • backend/FwLite/FwLiteShared/Services/FwLiteJson.cs
  • backend/FwLite/FwLiteShared/TypeGen/ChangeTypesCodeGenerator.cs
  • backend/FwLite/FwLiteShared/TypeGen/ReinforcedFwLiteTypingConfig.cs
  • backend/FwLite/FwLiteWeb/FwLiteWebKernel.cs
  • backend/FwLite/LcmCrdt.Tests/ConfigRegistrationTests.cs
  • backend/FwLite/LcmCrdt.Tests/Data/MigrationTests.cs
  • backend/FwLite/LcmCrdt.Tests/DataModelSnapshotTests.cs
  • backend/FwLite/LcmCrdt.Tests/EntityCopyMethodTests.cs
  • backend/FwLite/LcmCrdt.Tests/MiniLcmApiFixture.cs
  • backend/FwLite/LcmCrdt.Tests/TestJsonOptions.cs
  • backend/FwLite/LcmCrdt/CrdtProjectsService.cs
  • backend/FwLite/LcmCrdt/Data/SetupCollationInterceptor.cs
  • backend/FwLite/LcmCrdt/HistoryService.cs
  • backend/FwLite/LcmCrdt/Json.cs
  • backend/FwLite/LcmCrdt/LcmCrdtDbContext.cs
  • backend/FwLite/LcmCrdt/LcmCrdtKernel.cs
  • backend/FwLite/LcmCrdt/MediaServer/LcmMediaService.cs
  • backend/FwLite/LcmCrdt/SnapshotAtCommitService.cs
  • backend/FwLite/LcmDebugger/FakeSyncSource.cs
  • backend/Testing/FwHeadless/Services/SyncWorkerTestHarness.cs

Comment on lines +33 to +35
services.AddOptions<JsonOptions>().PostConfigure<IOptions<HarmonyConfig>>((jsonOptions, harmonyConfig) =>
{
jsonOptions.SerializerOptions.TypeInfoResolver = crdtConfig.Value.MakeLcmCrdtExternalJsonTypeResolver();
jsonOptions.SerializerOptions.TypeInfoResolver = harmonyConfig.Value.MakeLcmCrdtExternalJsonTypeResolver();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== AGENTS files =="
git ls-files | grep 'AGENTS\.md$' | sed -n '1,80p'

echo "== Locate relevant files =="
fd -a 'FwLiteWebKernel\.cs|FakeSyncSource\.cs|HarmonyConfig\.*|LcmCrdtKernel\.*|JsonOptions' . | sed 's#^\./##'

echo "== Search relevant symbols =="
rg -n "MakeLcmCrdtExternalJsonTypeResolver|MakeLcmCrdtExternalJsonOptions|JsonSerializerOptions|Change.*Converter|IChange|RegisterJsonConverters|Converters" -S .

Repository: sillsdev/languageforge-lexbox

Length of output: 45814


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== backend/FwLite/AGENTS.md =="
cat -n backend/FwLite/AGENTS.md

echo "== backend/FwLite/FwLiteWeb/FwLiteWebKernel.cs =="
cat -n backend/FwLite/FwLiteWeb/FwLiteWebKernel.cs

echo "== backend/FwLite/LcmDebugger/FakeSyncSource.cs =="
cat -n backend/FwLite/LcmDebugger/FakeSyncSource.cs

echo "== backend/FwLite/LcmCrdt/Json.cs relevant section =="
cat -n backend/FwLite/LcmCrdt/Json.cs | sed -n '230,275p'

echo "== ChangeSerializationTests relevant section =="
cat -n backend/FwLite/LcmCrdt.Tests/Changes/ChangeSerializationTests.cs | sed -n '1,170p'

echo "== Find sync/web tests involving JsonOptions/IChange =="
rg -n "IOptions<JsonOptions>|JsonOptions|IChange|ChangeEntity<IChange>|SyncState|ServerCommit|FromJsonFile" backend/FwLite/FwLiteWeb backend/FwLite/LcmCrdt.Tests backend/FwLite/FwLiteProjectSync.Tests -S

Repository: sillsdev/languageforge-lexbox

Length of output: 43916


🏁 Script executed:

#!/bin/bash
set -euo pipefail

dotnet --version 2>/dev/null || true
dotnet --list-sdks 2>/dev/null || true

git ls-files | rg '(\.(csproj|props|targets|slnf|json)$)' | sed -n '1,120p'

echo "== target frameworks and package versions =="
rg -n "<TargetFramework|<TargetFrameworks|<Harmony|SIL\.Harmony|PackageReference" backend/FwLite -S

echo "== project files containing FwLiteWeb and LcmDebugger =="
cat -n backend/FwLite/FwLiteWeb/FwLiteWeb.csproj 2>/dev/null || true
cat -n backend/FwLite/LcmDebugger/LcmDebugger.csproj 2>/dev/null || true

Repository: sillsdev/languageforge-lexbox

Length of output: 50386


Use Harmony’s full Web JSON options when parsing sync payloads.

JsonOptions and FakeSyncSource build Web options but only assign Harmony’s type resolver, so ChangeEntity<IChange> change fields still deserialize without Harmony’s IChange polymorphism converter. Use MakeLcmCrdtExternalJsonOptions() and/or copy JsonSerializerOptions.Converters, and add web/debugger coverage for a sync payload containing IChange.

📍 Affects 2 files
  • backend/FwLite/FwLiteWeb/FwLiteWebKernel.cs#L33-L35 (this comment)
  • backend/FwLite/LcmDebugger/FakeSyncSource.cs#L46-L51
🤖 Prompt for 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.

In `@backend/FwLite/FwLiteWeb/FwLiteWebKernel.cs` around lines 33 - 35, The web
and debugger sync JSON configuration only copies Harmony’s type resolver,
omitting its converters needed for IChange polymorphism. Update the JsonOptions
configuration in FwLiteWebKernel.cs and the web-options setup in
FakeSyncSource.cs to reuse MakeLcmCrdtExternalJsonOptions() or copy its
JsonSerializerOptions.Converters, and add web/debugger coverage for a sync
payload containing ChangeEntity<IChange>.

hahn-kev and others added 3 commits July 24, 2026 12:13
CodeRabbit flagged that FwLiteWebKernel's JsonOptions and FakeSyncSource built
Web options with only Harmony's type resolver, so ChangeEntity<IChange> fields
in sync payloads deserialized without Harmony's IChange polymorphism converter
(the same break the Refit client hit).

- FwLiteWebKernel: copy both the resolver and Harmony's converters from
  MakeLcmCrdtExternalJsonOptions onto the ASP.NET SerializerOptions.
- FakeSyncSource.FromJsonFile and TestJsonOptions.External: use
  MakeLcmCrdtExternalJsonOptions instead of a resolver-only options object.
- Add a regression test round-tripping every change type as IChange through the
  external options.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@myieye myieye left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Just a few thoughts. Looks good 👍

Comment on lines +38 to +41
var externalOptions = harmonyConfig.Value.MakeLcmCrdtExternalJsonOptions();
jsonOptions.SerializerOptions.TypeInfoResolver = externalOptions.TypeInfoResolver;
foreach (var converter in externalOptions.Converters)
jsonOptions.SerializerOptions.Converters.Add(converter);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I wonder if this should maybe happen inside or in a sibling method of MakeLcmCrdtExternalJsonOptions? It's not obvious here what things from MakeLcmCrdtExternalJsonOptions need to be copied over, but it is obvious where MakeLcmCrdtExternalJsonOptions is defined.

/// </remarks>
public static JsonSerializerOptions MakeLcmCrdtExternalJsonOptions(this HarmonyConfig config)
{
var options = new JsonSerializerOptions(JsonSerializerDefaults.Web)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I just learned about JsonSerializerOptions.MakeReadOnly().

It's probably not really worth anything caching and reusing a read-only copy of these options is it? It looks like only the RefitSettings take the whole object as is, so it presumably wouldn't cost us more memory, but...the benefit is just a tiny bit of startup time I guess?

/// server response throws "Deserialization of interface or abstract types is not supported. Type
/// 'SIL.Harmony.Changes.IChange'".
/// </remarks>
public static JsonSerializerOptions MakeLcmCrdtExternalJsonOptions(this HarmonyConfig config)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Are we gonna later rename LcmCrdt => LcmHarmony? 🙃

public static IReadOnlyList<RegisteredChangeType> AllRegisteredChanges()
{
var harmonyConfig = new HarmonyConfig();
ConfigureCrdt(harmonyConfig);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Somewhat unrelated to your changes, but:
ConfigureCrdt() looks like a fairly heavy method.
It's invoked for building the list of change types on the history page.
Is it a cache candidate?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

oh, well there we should just be injecting HarmonyConfig and using that since it's already setup in an IOC conatiner. This is really mostly a helper for tests.

}

public static void ConfigureCrdt(CrdtConfig config, bool addRemoteResourceEntity = true)
public static void ConfigureCrdt(HarmonyConfig config, bool addRemoteResourceEntity = true)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I suppose there are a bazillion things you could consider renaming.
This is just one example and you don't want to chase them all down, so just rename what you feel like renaming. Crdt is probably still the correct term in some contexts.

Suggested change
public static void ConfigureCrdt(HarmonyConfig config, bool addRemoteResourceEntity = true)
public static void ConfigureHarmony(HarmonyConfig config, bool addRemoteResourceEntity = true)

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 📦 Lexbox issues related to any server side code, fw-headless included

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants