Kgothatso Ngako eb34c8edb3 feat: sign a chapter into the artifact instead of submitting one
Adding a chapter no longer creates one. It opens a signing session over a
ChapterEvent, and the chapter appears -- on every member's device at once,
authored by the room's shared key rather than by whoever pasted the text --
when enough members have signed. The same trade the dialects and artifacts
made: a submission says "I am putting this in front of the group" and the
group's only recourse afterwards is social, while a signature is the group
saying it and it takes a quorum to say. The text everybody translates from is
the group's, so the second is the honest one.

**The chunks.** This is the part chapters had that dialects and artifacts did
not. A chapter was submitted along with a ChunkEvent per paragraph, and that
cannot survive the change: a translation is of a chunk rather than of a
chapter, so a chapter without them cannot be worked on, but the chunks cannot
have their own quorum without costing one signing session per paragraph, and
they cannot be invented locally -- an invented id differs on every device, so
members would silently disagree about which chunk a translation is of while
every screen showed the same chapter.

So the chunks are split back out of the signed chapter's own text when it is
applied, in MantraChunk.chunksOf, on the pattern
MantraArtifactVersion.initialVersionOf already set. Same bytes in, same rows
out, everywhere. They are rumors, because nobody signed them; what the group
signed is the chapter they were split from.

It splits only what the group signed. A chapter that arrived as a submission
was sent with its own chunk events, written under the submitter's key, and
deriving a second set beside them would leave every paragraph in the chapter
twice under ids nothing reconciles -- including on a marmot reindex, which
replays a room's group events without anybody adding anything.

**The index.** Where a chapter sits in its version is read at proposal time
and signed into the event, rather than derived on arrival like the chunks
are. A device applying the chapter cannot recount it: it would be counting a
version other members may have added to in a different order, and the count
has to be the one the group put its signature to. The window between proposal
and quorum is longer than the old write-and-submit window was, so two chapters
proposed at once can still land on one index -- the same race as before, wider.

**What went away.** MantraDao.addChapter and its way up through the repository.
Nothing called it once the screen proposed instead, and leaving a path that
authors a chapter under a member's key while the UI insists on a quorum would
have double-created the chunks besides. MantraRepository.getChaptersForArtifactVersion
replaces the one thing it did that is still needed: counting the index.

**The screens.** AddChapterScreen loads the room, the artifact's latest
version and canSign up front, disables the FAB when either is missing the way
the dialect and artifact screens do, and on success lands on the session
rather than on an artifact the chapter is not in yet. FrostSigningScreen
described a chapter proposal by name alone, so a member was asked to sign text
whose size they could not see; it now reads name, word count and chunk count,
the way an artifact shows its url.

**Tests.** Two files, and each was checked against a broken implementation
rather than only against a working one: deriving the chunks from the clock,
inheriting the chapter's counts across every chunk, authoring the derived rows
as their reader, and losing the paragraph position are all caught, as is
splitting a chapter that arrived as a submission. SignedChapterTest runs a
real 2-of-3 quorum over an actual proposal, because the claim worth holding --
the chapter is the group's, carries proof of it, and every device splits it
into the same chunks -- is invisible when it breaks.

Not covered: applyInnerEvent's upserts, which need a database no test here
stands up, and AddChapterViewModel, which is plumbing across two dispatchers
over a template the tests already pin.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-06 04:15:36 +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%