Skip to content

Add variant model, CRDT changes, FwData bridge and sync (1/3)#2416

Draft
myieye wants to merge 24 commits into
developfrom
feat/variants-model-sync
Draft

Add variant model, CRDT changes, FwData bridge and sync (1/3)#2416
myieye wants to merge 24 commits into
developfrom
feat/variants-model-sync

Conversation

@myieye

@myieye myieye commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

Adds variant relationships to FwLite — model, CRDT changes, FwData bridge, and FwData↔CRDT sync. Editor UI is a follow-up.

  • A Variant link maps to one FieldWorks LexEntryRef (RefType=Variant): per-link ordered Types, HideMinorEntry, Comment.
  • ⚠️ Cycle checks now span the combined complex-form + variant graph, so AddEntryComponentChange replay changes for every complex-form project — see VARIANTS.md (decision 7).
  • Design, decisions, and rollout notes: backend/FwLite/VARIANTS.md.

Tested by conformance suites on both IMiniLcmApi implementations, FwData↔CRDT round-trip sync, and a seeded differential oracle against liblcm's cycle rule.

myieye and others added 20 commits July 6, 2026 15:13
One Variant link = one LexEntryRef (RefType=Variant) with per-link Types,
HideMinorEntry and Comment (LCM Summary), per VARIANTS.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Conformance suites for both IMiniLcmApi implementations, change/usage/serialization
tests, verified-file regens, AutoFaker support. LCM enforces acyclicity over the
combined complex-form + variant graph, so AddVariantChange mirrors that check.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Regenerated via ProjectTemplateTests.GenerateTemplate; new CRDT projects get the
7 standard FLEx variant types (well-known guids), matching FieldWorks.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Variant lists sort by composite key on both sides (deterministic, culture-free);
BulkCreateEntries emits variant links; regenerated Sena3 live db + snapshots —
sena-3's real variants (custom Pronunciation Variant type) now round-trip.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A sense-targeted variant link is identified by its full composite key; the FwData
bridge matched by sense guid alone, so a moved sense made the sync drop the link
(new regression test covers both implementations).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…riant entry id

Both implementations now reject a MainSenseId that belongs to a different entry
(fail before mutation); EntryValidator requires VariantEntryId on Variants items.
Also corrects the stale cycle-guard decision text in VARIANTS.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Cycle checks now share one liblcm-faithful walk (ComponentGraph): sense-targeted
  links resolve to the owning entry without recursing (LexEntry.AllComponents), and
  AddEntryComponentChange walks the combined complex-form + variant graph like
  liblcm instead of complex forms only
- Per-link edits split a shared (multi-component) variant ref before mutating so
  sibling links keep their own Types/HideMinorEntry/Comment
- Variant reads skip non-entry/non-sense components instead of wedging the entry
- HideMinorEntry only written when the bool view flips (LCM reserves a bitfield)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…itfield

Mutation-tested the new cycle/shared-ref guards (3/3 mutants killed); the
surviving would-be mutant exposed the missing HideMinorEntry bitfield test.
Also docs: fleet-skew rollout note for AddEntryComponentChange, badge and
type-seeding follow-ups, SubmitUpdateVariant asymmetry rationale.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- BeaKona forwarders bypassed validation on SubmitCreateVariant and
  SubmitUpdateVariant; both now validate (same class of gap as #2362)
- New VariantUpdateValidator rejects patches to Types (incl. by index,
  via new DoesNotChangePropertyOrChildren), endpoints, derived
  headwords, DeletedAt and Id
- VariantType and ComplexFormType names now reject empty per-WS values
- CreateEntryOptions.IncludeComplexFormsAndComponents renamed to
  IncludeEntryReferences (it gates variants too); generated TS updated
- BoolDiff helper (mirrors IntegerDiff); ToVariants flattened to
  Concat; FluentAssert Id-exclusion no longer names one type''s members;
  ProjectSnapshot.VariantTypes legacy-null note sharpened

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
FLEx lets users reorder a ref''s VariantEntryTypesRS (right-click, move
left/right); syncing types as a set silently lost that order. Adds
SetVariantTypesOrder to IMiniLcmWriteApi (both implementations, dry-run,
wrappers, notify) and SetVariantTypesOrderChange (unlisted types keep
their relative order after listed ones, so concurrent type adds merge).
VariantSync resets order after the add/remove diff whenever it cannot
have landed in after-order. Variant link lists themselves stay
unordered (decision 6, amended).

Covered by shared conformance tests (both impls), a CRDT change test
incl. the concurrent-add merge, and a full FwData<->CRDT sync
round-trip; change-model/regression verified files regenerated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The whole-list SetVariantTypesOrderChange clobbered concurrent
reorders; per Tim''s review, type order now works like sense pictures:
Variant.Types holds VariantTypeRef objects ({typeId, fractional Order},
which also removes the stale-embedded-Name wart from decision 8),
AddVariantType takes a BetweenPosition, MoveVariantType replaces the
list-order API, and ReorderVariantTypeChange merges per type under
concurrency. VariantSync diffs types with DiffOrderable.

Regenerated: change/snapshot regression data (old branch-era shapes
auto-migrated to the legacy files; the never-shipped
SetVariantTypesOrderChange entry removed), DbModel/ChangeModels
snapshots, sena-3-live snapshot, TS types (IVariantTypeRef).

(The field-editor adaptations live in the stacked editor-UI branch.)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…l-sync

# Conflicts:
#	backend/FwLite/LcmCrdt.Tests/Changes/ChangeDeserializationRegressionData.latest.verified.txt
#	backend/FwLite/LcmCrdt.Tests/Changes/ChangeDeserializationRegressionData.legacy.verified.txt
#	backend/FwLite/LcmCrdt.Tests/Data/SnapshotDeserializationRegressionData.latest.verified.txt
#	backend/FwLite/LcmCrdt.Tests/Data/SnapshotDeserializationRegressionData.legacy.verified.txt
#	backend/FwLite/LcmCrdt.Tests/DataModelSnapshotTests.VerifyDbModel.verified.txt
#	backend/FwLite/LcmCrdt/Migrations/LcmCrdtDbContextModelSnapshot.cs
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

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: 8d936804-98e9-4126-839d-8319ebcc1515

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
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/variants-model-sync

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 6, 2026
@argos-ci

argos-ci Bot commented Jul 6, 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 7, 2026, 2:16 PM

@myieye myieye marked this pull request as draft July 6, 2026 14:09
myieye and others added 4 commits July 6, 2026 17:05
Submit* are the sync's result-less fire-and-forget writes (delete-wins on a
concurrently-deleted target). The write-normalization wrapper's un-overridden
Submit* silently downgrade that to a throwing update via the interface default
body, so add SubmitCreateVariant + SubmitUpdateVariantType overrides (forward to
_api.Submit*), plus tests asserting normalization and Times.Never on the
returning method. Documents the rule in FwLite AGENTS.md and the interface.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adding a variant type during sync (VariantSync → AddVariantType, and
SubmitCreateVariant for a whole link) threw when the type had been concurrently
deleted on the other replica, wedging the entire project sync. Both IMiniLcmApi
implementations now drop the missing type (delete wins), matching
Remove/MoveVariantType and AddVariantChange.NewEntity, which already tolerated
it. New conformance tests (both implementations) fail without the fix.

Also: exclude Variant.Types[].Order from the CanSyncRandomEntries round-trip
comparison — it was the only Order field not excluded, and the write path
normalizes it like every other orderable, which was the red CI. And correct
stale VARIANTS.md type-ordering docs + soften unverified FLEx-UI comments.

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

# Conflicts:
#	backend/LfClassicData/LfClassicMiniLcmApi.cs
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.

1 participant