Adding an artifact no longer creates one. It opens a signing session over an ArtifactEvent, and the artifact 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. The same trade the dialects 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. A library is the group's. **The first version.** This is the part the dialect had no answer for. An artifact was creating an initial ArtifactVersion as a second submitted event, and that cannot survive the change: a chapter attaches to a version rather than to an artifact, so an artifact without one is inert, but a version cannot be submitted before the artifact it points at exists, cannot have its own quorum without costing a second signing session per form, and cannot be invented locally -- an invented id differs on every device, so members would silently disagree about which version a chapter hangs off while every screen showed the same artifact. So the label rides on the artifact as an `artifactVersion` tag and the row is derived from the signed artifact's own fields when it is applied. Same bytes in, same row out, everywhere. It is a rumor, because nobody signed it; what the group signed is the artifact that declares it. **What went away.** MantraDao.addArtifact and its way up through the repository. Nothing called it once the screen proposed instead, and leaving a path that authors an artifact under a member's key while the UI insists on a quorum would have double-created the version besides. **Tests.** Three files, and each was checked against a broken implementation rather than only against a working one: deriving the version from the clock, dropping the label from the proposal, authoring the derived row as its reader, and losing the signature on the way out of the session are all caught. SignedArtifactTest runs a real 2-of-3 quorum over an actual proposal, because the claim worth holding -- the row is the group's, and carries proof of it -- is invisible when it breaks. Not covered: applyInnerEvent's two upserts, which need a database no test here stands up, and AddArtifactViewModel, which is plumbing across two dispatchers over a template the tests already pin. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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 that’s 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 Apple’s 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 you’re 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 IDE’s 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 IDE’s 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 IDE’s toolbar or open the /iosApp directory in Xcode and run it from there.
Learn more about Kotlin Multiplatform…