Kgothatso Ngako 76b4a78581 fix: keep one translation per source chunk, however it arrives
A translation chunk is never edited. Retranslating a passage means a new event
carrying new words, and an event's id is a hash over its content -- so the
second translation is a row of its own rather than an overwrite of the first.

`MantraDao.saveTranslation` knew that and dropped the row it superseded, but it
only ever saw this device's own retranslations. Everything arriving from the
group went through `ChatMessage.applyInnerEvent`, which upserted and nothing
else. A member retranslating a passage somebody else had already translated left
two rows behind, and `TranslationChapterViewModel` pairs chunks with their
translations by `associateBy { it.chunkId }` -- one of the two wins, and which
one is whatever order SQLite happened to return them in for a query ordered on a
column they share.

So the rule moves to where the row is actually made, and now covers the group's
signatures and the relay's deliveries alike.

**Newest wins by the timestamp the group signed at, not by arrival.** Two
devices catching up read the same events in whatever order their relays hand
them over, and they have to end up holding the same translation either way. An
older translation arriving after the one that superseded it is dropped rather
than allowed to overwrite it. Ties break on the event id -- arbitrary, but the
same arbitrary on every device, which is the whole requirement.

**Matched on the source chunk, not on the chapter.** A chapter holds one
translation per passage, not one translation; matching on the chapter alone
would leave a chapter that could only ever show its most recently translated
paragraph. `getTranslationChunksByChunkId` is the query that says so.

**Tests.** `TranslationChunkApplyJvmTest` covers the three cases against a real
database: a retranslation replaces what it supersedes, a translation arriving
after the one that superseded it is dropped, and two chunks of one chapter each
keep their own. The first two fail against the plain upsert this replaces; the
third is what stops the fix from over-deleting.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-06 13:13:50 +02:00
2026-07-05 23:21:02 +02:00
2026-07-28 09:10:20 +02:00
2026-03-24 04:47:19 +02:00
2026-03-23 01:41:39 +02:00
2026-03-23 01:41:39 +02:00
2026-03-23 01:41:39 +02:00

This is a Kotlin Multiplatform project targeting Android, iOS, Desktop (JVM).

  • /composeApp is for code that will be shared across your Compose Multiplatform applications. It contains several subfolders:

    • commonMain is for code thats common for all targets.
    • Other folders are for Kotlin code that will be compiled for only the platform indicated in the folder name. For example, if you want to use Apples CoreCrypto for the iOS part of your Kotlin app, the iosMain folder would be the right place for such calls. Similarly, if you want to edit the Desktop (JVM) specific part, the jvmMain folder is the appropriate location.
  • /iosApp contains iOS applications. Even if youre sharing your UI with Compose Multiplatform, you need this entry point for your iOS app. This is also where you should add SwiftUI code for your project.

Build and Run Android Application

To build and run the development version of the Android app, use the run configuration from the run widget in your IDEs toolbar or build it directly from the terminal:

  • on macOS/Linux
    ./gradlew :composeApp:assembleDebug
    
  • on Windows
    .\gradlew.bat :composeApp:assembleDebug
    

Build and Run Desktop (JVM) Application

To build and run the development version of the desktop app, use the run configuration from the run widget in your IDEs toolbar or run it directly from the terminal:

  • on macOS/Linux
    ./gradlew :composeApp:run
    
  • on Windows
    .\gradlew.bat :composeApp:run
    

Build and Run iOS Application

To build and run the development version of the iOS app, use the run configuration from the run widget in your IDEs toolbar or open the /iosApp directory in Xcode and run it from there.


Learn more about Kotlin Multiplatform

Description
Mantra as a kotlin multiplatform project
https://mantra.press
Readme 8.2 MiB
Languages
Kotlin 100%