Kgothatso Ngako 3e4166f13d feat: sign a dialect into existence instead of submitting one
Adding a dialect no longer creates one. It opens a signing session over a
DialectEvent, and the dialect appears -- on every member's device at
once, authored by the group's shared key rather than by whoever typed it
-- when enough members have signed.

That is the difference between the two envelopes. A submission says "I am
putting this in front of the group"; the group's only recourse afterwards
is social, and the row records the submitter as its author. A signature
is the group saying it, it takes a quorum to say, and the author on the
row is the group's key. For something as load-bearing as the set of
dialects a group translates into, the second is the honest one.

**Where the signed event becomes a row.** Every device has the event and
the signature once the session completes, so each applies the result
itself rather than waiting to be sent something it can already build --
the same reasoning the transcript lines are written on. Nothing goes on
the wire for it, and nothing could: the outbound pipeline re-authors
rumors as their sender, so a group-signed event pushed through it would
come out stripped of the signature and attributed to whoever sent it.

Applying reuses the inbound path's dispatch rather than repeating it.
applyInnerEvent takes plain ids now instead of a GroupEvent, and both are
null here, because there is no group event and no inner event behind a
row a device derived for itself. A failure there is logged and the
session still completes: the signature is made and valid, and failing the
session would tell the group to abandon something that succeeded.

**The screen.** One, not three. A ceremony asks three different questions
so it gets three approval screens; signing asks one -- sign this or do
not -- so a single screen has to carry the whole case: what is being
signed, who else has agreed, and what the group is still waiting on. The
event is shown as the thing it is, a dialect with its name and country
and language, because a member deciding whether to sign is deciding about
a dialect and "kind 30304" answers a question nobody asked. Anything
unrecognised falls back to the raw kind, which is better than describing
it wrongly.

The member ladder names people rather than counting them, for the same
reason the ceremony's does: "1 of 2" does not tell anyone whose door to
knock on. It stays useful after the decision, since a member who has
already signed is exactly who needs to see who has not.

**Getting there.** Signing lines render in the transcript as system
notices like ritual lines -- nobody said them either -- but they lead to
the session rather than to the key. A chat row carries no session id and
adding a column to the table every message uses would be a poor trade for
a lookup, so FrostSigningRoute takes a nullable id and the screen
resolves the room's live session. Approving is recorded as answered by
the nonce line rather than the partial signature: agreeing is agreeing to
take part, and the coordinator may then pick a quorum without you, which
should not leave you looking like you never replied.

**Proposing needs a key.** The FAB is disabled, and says why, when the
room has none -- proposeSigning throws there, and it is not reachable
outside the #admins room in the first place. AddDialectViewModel drops
MantraRepository, which it no longer uses for anything.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 22:09:47 +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%