Add main publication to new entries (IsMain)#2341
Conversation
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
C# FwHeadless Unit Tests48 tests 48 ✅ 17s ⏱️ Results for commit f4b932f. ♻️ This comment has been updated with latest results. |
C# Unit Tests165 tests 165 ✅ 20s ⏱️ Results for commit f4b932f. ♻️ This comment has been updated with latest results. |
|
The latest updates on your projects. Learn more about Argos notifications ↗︎
|
|
|
||
| var publications = await Api.GetPublications().ToArrayAsync(); | ||
| publications.Should().ContainSingle(p => p.IsMain).Which.Id.Should().Be(firstMainId); | ||
| publications.Should().NotContain(p => p.Id == secondMainId); |
There was a problem hiding this comment.
is deleting the right move? what if we just kept it around but made sure it's not main? There's going to be entries that reference this publication (because it was main for this user) so deleting it will remove the publication from those entries.
There was a problem hiding this comment.
I agree. I'll change it to keep the new publication and simply not mark it as "main"
There was a problem hiding this comment.
we should consider what BulkCreateEntries does. Right now it will bulk create entries without a publication. But maybe we just need to add CreateEntryOptions to the bulk api.
There was a problem hiding this comment.
Oh, yikes. Actually, we're falling back to CreateEntryOptions.Everything, which does auto-add the main publication, which is actually really bad. When we're importing entries from FieldWorks we shouldn't touch anything. If there are entries not in the main publication, then that's intentional.
There was a problem hiding this comment.
I've renamed Everything to AsIs and it no longer auto-adds the main publication. It does exactly was it says: it creates the entry as-is.
hahn-kev
left a comment
There was a problem hiding this comment.
looks good to me. I tested it locally against a FW project and it worked great. I don't have any existing projects locally and downloading new ones is broken by morph types right now so I can't test that.
5666b93 to
347d2c8
Compare
…sMain Replace the timestamp-based default publication tracking with a simple boolean flag. This makes finding the main/default publication a direct flag check rather than requiring date comparisons. Key behaviors: - API methods throw if turning IsMain from ON to OFF - API methods throw if setting IsMain ON for more than one publication - CRDT SetDefaultPublicationChange is a no-op if a main publication already exists (0→1 transition only), ensuring convergence - FwData bridge maps IsMain from/to FW's IsProtected property - IsMain is stripped when syncing back to FwData (read-only there) - CreateEntry auto-adds the default publication when enabled https://claude.ai/code/session_01YJVmNMUDdWKgGUv3HicCCo
The Publication model uses IsMain, so all related code should use "main" terminology consistently instead of mixing "default" and "main". Renames across backend and frontend: - SetDefaultPublicationChange → SetMainPublicationChange - GetDefaultPublication → GetMainPublication - AutoAddDefaultPublication → AutoAddMainPublication - defaultPublication → mainPublication - resolveDefaultPublication → resolveMainPublication - UI text: "default publication" → "main publication" https://claude.ai/code/session_01YJVmNMUDdWKgGUv3HicCCo
The IsMain column (added in the publication refactor) had no migration. The local dotnet-ef tool was pinned to 9.0.16 while the project targets EF Core 10.0.8, so the snapshot was stamped 9.0.16; bump the tool to 10.0.8 and scaffold the migration + snapshot with matching tooling. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Guard CreatePublication/UpdatePublication on both API implementations so a second main publication can't be created and the main flag can't be turned off. For CRDT merges (where two replicas can each create a main offline), CreatePublicationChange returns the duplicate pre-deleted so Harmony filters it out, converging to one main without throwing. GetMainPublication uses SingleOrDefault to surface >1 corruption rather than mask it. AutoFaker now forces Publication.IsMain false: main is a controlled singleton, never randomly generated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The publication rename added "The main publication is always included." in NewEntryDialog without re-extracting the catalogs, failing the i18n check. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The demo API's publications omitted the now-required isMain, failing svelte-check; the publications unit test used `as any`, failing eslint. Set isMain on the demo publications (Main Dictionary is the main one) and type the test with a small IPublication factory. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The workaround forced IsMain=false on both sides before the CRDT->FwData publication sync. It was masking AutoFaker generating publications with random IsMain=true, which let a test create a CRDT main different from FwData's protected main. With faked publications now always IsMain=false, the two sides always agree on the main, so no IsMain write-back is ever needed — and FwData's IsMain is read-only anyway (UpdatePublicationProxy.IsMain is a no-op, mapped from IsProtected). Sync publications symmetrically like every other entity. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CreateEntry auto-adds the main publication by default (a UI affordance), so in FwData — which always has a protected Main Dictionary — entries the query tests expect to have an empty PublishIn instead carry the main. Disable auto-add where those tests assert exact PublishIn, matching the sync path (EntrySync), which also never auto-adds. Regenerate the Sena-3 snapshot for the new IsMain field. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
When the main publication is new to a collection, PublicationSync's Add already creates it with IsMain set, so the follow-up collection-level UpdatePublication was redundant — and it threw NotFound during a dry-run sync, where the Add was a no-op so the publication doesn't actually exist. Only promote a publication that already existed but wasn't yet the main. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Approve the developer-approval snapshots for the new IsMain field and SetMainPublicationChange: the change/snapshot regression data, the EF model and change-model snapshots, and the live Sena-3 db + fw-headless snapshot (one-time SetMainPublicationChange promoting the protected Main Dictionary to main). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…motion Flip CreateEntryOptions.AutoAddMainPublication to default off so bulk import and sync preserve the source's publications; interactive entry creation opts in via the new CreateEntryOptions.WithMainPublication (passed at the JS-invokable, hub, and route entry points). Rename CreateEntryOptions.Everything to AsIs. On offline merge, a duplicate main publication is now demoted to a non-main publication instead of being deleted, so the publication survives. Gate the NewEntryDialog publish-in note on field visibility. Adds PublicationSync tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…t scope AGENTS.md: note that MiniLcm.Tests / LcmCrdt.Tests / FwDataMiniLcmBridge.Tests run without infrastructure (FwData-backed ones moderately slow, so filter). i18n-completeness: drop the translator-context (#.) comment check, owned by the crowdin-merge workflow. Restore trailing newline in dotnet-tools.json. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…reateEntry options Move the single-main guards out of the CRDT and FwData APIs into the shared MiniLcmApiValidationWrapper (new PublicationUpdateValidator + a TryGetPropertyChange helper), so the invariant lives in one place; CrdtMiniLcmApi keeps only the SetMainPublicationChange convergence. Make the JS-invokable CreateEntry options a required argument (optional [JSInvokable] params throw at runtime on arg-count mismatch, despite type-checking) and drive AsIs vs WithMainPublication from the frontend by publish-in field visibility, via a shared TS helper mirroring the C# presets. Simplify the publishIn handling. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add the UpdatePublication(before, after) override to MiniLcmApiValidationWrapper so the publication update path validates its model like every other entity does — it was the one gap in the publication wrapper overrides. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ESLint's @typescript-eslint/naming-convention rejects PascalCase const variables; the shared options helper must be camelCase. svelte-check didn't catch it (it's a lint rule). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The IsMain refactor edited sena-3_snapshot.2026-04-09.verified.txt in place. Dated snapshots are immutable historical fixtures (AssertSena3Snapshots iterates them to prove old formats still deserialize), and every prior format change added a new dated file rather than mutating an existing one. Restore 2026-04-09 to its pre-IsMain content and capture the IsMain round-trip output as a new 2026-06-18 snapshot, which LatestSena3SnapshotRoundTrips now targets. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…inputs Closes #2366. The newest dated sena-3 snapshot used to do two fighting jobs: an immutable historical deserialize fixture (AssertSena3Snapshots) and the mutable round-trip Verify target (LatestSena3SnapshotRoundTrips, picked via OrderDescending().First()). A format change tempted editing a dated file in place, which silently rotted the back-compat guard. Split them: the dated files are now deserialize-only inputs that never change, and an un-dated sena-3_snapshot.latest.verified.txt is the round-trip target that legitimately tracks the current format. The IsMain snapshot added earlier on this branch becomes that latest file. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…uded" string An earlier iteration of NewEntryDialog showed this note inline; it later moved to the publishInNote snippet and the string is no longer used, but the catalogs still carried it. Re-running extraction prunes it from all locales. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…d dated inputs" This reverts commit 4ed9776.
The IsMain migration was generated with EF tools 10, but bumping .config/dotnet-tools.json is unrelated to this PR. Restore develop's 9.0.16. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Use the named helper in EntrySync instead of constructing the options inline. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ions The hub and REST route hardcoded WithMainPublication; now they accept an optional options arg, defaulting to the same behaviour (auto-add the main publication). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Skip allocating a filtered JsonPatchDocument on the common update that doesn't touch IsMain. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
DiffToUpdate now carries the false->true promotion like any other field (the CRDT side turns it into a SetMainPublicationChange), so the collection-level promotion special-case is removed. A main is never demoted, so there's no 1->0 handling to add. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The single-main guards are enforced in the backend-agnostic validation wrapper, so move them to PublicationsTestsBase. FwData maps IsMain from the read-only IsProtected, so the FwData test seeds a main at the LCM layer. The promotion and merge-convergence tests stay CRDT-only. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
5388d3c to
1bb7c5a
Compare
Consolidate the get-or-create main-publication helper onto MiniLcmTestBase (shared by the publication and create-entry conformance tests, reusing the project's existing main rather than minting a second). Make the REST route's CreateEntryOptions defaults explicit via ToOptions(defaults), extract CreatePublicationChange.MainAlreadyExists, and make DoesNotChangePropertyTo generic over the forbidden value's type. Drop the dry-run PublicationSyncTests: the collection-level promotion it guarded was removed when IsMain moved into standard per-publication diffing, so the failure mode it covered is structurally gone. Fix entry-api-helper to inline the create-entry options inside page.evaluate — module imports are closure variables that don't cross the Playwright serialization boundary, so referencing the shared helper there throws. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The hand-minimized latest.verified.txt left a trailing comma after LexemeForm, which strict deserialization (CanDeserializeLatestRegressionData) rejects and RegressionDataUpToDate flagged. Drop it; data is otherwise unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fixes #2179.
FieldWorks marks one publication ("Main Dictionary") as protected and auto-adds it to every new entry, so downstream workflows (Webonary export, etc.) pick up new entries by default. FwLite didn't. This adds an
IsMainflag onPublication(read from FLEx's protectedIsProtectedon import, not written back) and lets new-entry creation add the main publication.Whether a new entry gets the main publication is decided per call via
CreateEntryOptions(the C# presetsWithMainPublication/AsIs, mirrored by a small TS helper). The viewer chooses based on whether the user can see the "Publish in" field: if it's shown the user controls publications (AsIs), otherwise we auto-add the main (WithMainPublication). Bulk import and sync always useAsIs, so they preserve the source's publications.The single-main invariant (can't create a second main, can't turn the main flag off) lives in the shared
MiniLcmApiValidationWrapper, so it applies to both the CRDT and FwData backends in one place;CrdtMiniLcmApikeeps only the CRDT-specificSetMainPublicationChangeconvergence. Because two CRDT replicas can each create a main while offline, a merged-in duplicate is demoted to a non-main publication (not deleted), converging to one main without throwing or losing data.One deliberately odd bit: the JS-invokable
CreateEntrytakesoptionsas a required argument, not a nullable/optional one. Optional[JSInvokable]params are a lie — Blazor enforces argument count, so an omitted arg throws at runtime even though it type-checks. Making it required moves that failure to compile time.Includes an EF Core migration for the
IsMaincolumn (dotnet-ef bumped to 10.0.8 to match the project's EF Core version). Also rides along two unrelated hygiene tweaks (an AGENTS.md test-guidance clarification and an i18n-completeness agent scope trim), called out so they're not a surprise.Test plan
WithMainPublicationadds the main,AsIsdoesn't, no double-add; on both the CRDT and FwData APIs.PublicationSyncpromotes an existing publication to main, and a brand-new main is created (not promoted) so a dry-run sync doesn't throw.