Merge branch 'mantra' into claude/project-feature-plan-b58ab2

Eighteen commits of subgroup adoption and key-ceremony work, and one collision
that was the point of writing Phase 0 down.

**Schema.** `mantra` took 21 for `GroupKeyStateParent` -- a room's parentage as a
row, so it can have two -- as a manual `MIGRATION_20_21` that copies before it
drops. Projects had taken 21 on this branch. Neither had shipped, so projects
renumbered to **22**, an `AutoMigration(from = 21, to = 22)` on top of theirs;
`schemas/21.json` is now theirs and `22.json` is the two together, 58 tables.
docs/project-feature.md records it, including that Phase 0 told us to check for
exactly this and checked the sibling fork rather than the base branch.

Three conflicts. `MantraDatabase.kt` wanted both entity sets and both
migrations, and their v21 contributes only a comment there since the entry is
manual. `ProposedEventTest.kt` and the schema file were additive either way.

Nine files auto-merged, and `ChatMessage.kt` was the one to watch: they reshaped
the `SubgroupBirthCertificateEvent` arm while this branch added three project
arms to the same `when`. Git saw no conflict and the compiler agrees.

**One test fails, and it arrives with the merge rather than from it.**
`NavigationRoutingTest` reports "uncaught exceptions before the test started",
which is leakage, not its own failure: `CeremonyQueueRoutingJvmTest` (new in
b6c3e3dd) builds a `ChatMessageListViewModel` over
`NO_OP_NOSTR_REPOSITORY`, whose `queueNegentropySynchronizeRequest` is a
`TODO()`, and it throws on a background dispatcher. Whichever `runTest` starts
next is blamed, so it is order-dependent -- the same test passes alone and in
smaller selections. This branch touches neither `scheduleSynchronization` nor
`NostrRepository`; its only edit to that view model is the `summarize` call.

1051 jvmTest with that one failure, 482 testDebugUnitTest clean, m3Audit's
budgets all met.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Kgothatso NgakoandClaude Opus 5 committed 2026-10-02 20:48:17 +02:00
commit 3cd9001c27
57 files changed
+12661 -1055

No files matched your search

@@ -2,7 +2,7 @@
"formatVersion": 1,
"database": {
"version": 21,
"identityHash": "ccbc98e82860c74663f3faed72cd1395",
"identityHash": "ff296ccd92cdb4bd61b3e150565f59c4",
"entities": [
{
"tableName": "BroadcastNostrEventReceipt",
@@ -671,7 +671,7 @@
},
{
"tableName": "ChatRoom",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `userPublicKey` TEXT NOT NULL, `subject` TEXT, `description` TEXT, `mlsGroupState` TEXT, `initialGiftWrapPayloadId` TEXT, `leftGroupAt` INTEGER, `joinedGroupAt` INTEGER, `chronicleRequestedAt` INTEGER, `parentChatRoomId` TEXT, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, `savedAt` INTEGER NOT NULL, `viewedAt` INTEGER, `deletedAt` INTEGER, PRIMARY KEY(`id`), FOREIGN KEY(`userPublicKey`) REFERENCES `Profile`(`publicKey`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`initialGiftWrapPayloadId`) REFERENCES `GiftWrapPayload`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `userPublicKey` TEXT NOT NULL, `subject` TEXT, `description` TEXT, `mlsGroupState` TEXT, `initialGiftWrapPayloadId` TEXT, `leftGroupAt` INTEGER, `joinedGroupAt` INTEGER, `chronicleRequestedAt` INTEGER, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, `savedAt` INTEGER NOT NULL, `viewedAt` INTEGER, `deletedAt` INTEGER, PRIMARY KEY(`id`), FOREIGN KEY(`userPublicKey`) REFERENCES `Profile`(`publicKey`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`initialGiftWrapPayloadId`) REFERENCES `GiftWrapPayload`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "id",
@@ -720,11 +720,6 @@
"columnName": "chronicleRequestedAt",
"affinity": "INTEGER"
},
{
"fieldPath": "parentChatRoomId",
"columnName": "parentChatRoomId",
"affinity": "TEXT"
},
{
"fieldPath": "createdAt",
"columnName": "createdAt",
@@ -1619,7 +1614,7 @@
},
{
"tableName": "GroupKeyState",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`chatRoomId` TEXT NOT NULL, `dkgSessionId` TEXT NOT NULL, `thresholdPublicKey` TEXT NOT NULL, `derivationPath` TEXT NOT NULL, `announcedBy` TEXT NOT NULL, `announcedAt` INTEGER NOT NULL, `parentChatRoomId` TEXT, `birthCertificateJson` TEXT, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, `savedAt` INTEGER NOT NULL, PRIMARY KEY(`chatRoomId`), FOREIGN KEY(`chatRoomId`) REFERENCES `ChatRoom`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`chatRoomId` TEXT NOT NULL, `dkgSessionId` TEXT NOT NULL, `thresholdPublicKey` TEXT NOT NULL, `derivationPath` TEXT NOT NULL, `announcedBy` TEXT NOT NULL, `announcedAt` INTEGER NOT NULL, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, `savedAt` INTEGER NOT NULL, PRIMARY KEY(`chatRoomId`), FOREIGN KEY(`chatRoomId`) REFERENCES `ChatRoom`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "chatRoomId",
@@ -1657,16 +1652,6 @@
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "parentChatRoomId",
"columnName": "parentChatRoomId",
"affinity": "TEXT"
},
{
"fieldPath": "birthCertificateJson",
"columnName": "birthCertificateJson",
"affinity": "TEXT"
},
{
"fieldPath": "createdAt",
"columnName": "createdAt",
@@ -1717,6 +1702,61 @@
}
]
},
{
"tableName": "GroupKeyStateParent",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`chatRoomId` TEXT NOT NULL, `parentChatRoomId` TEXT NOT NULL, `birthCertificateJson` TEXT NOT NULL, PRIMARY KEY(`chatRoomId`, `parentChatRoomId`), FOREIGN KEY(`chatRoomId`) REFERENCES `GroupKeyState`(`chatRoomId`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "chatRoomId",
"columnName": "chatRoomId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "parentChatRoomId",
"columnName": "parentChatRoomId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "birthCertificateJson",
"columnName": "birthCertificateJson",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"chatRoomId",
"parentChatRoomId"
]
},
"indices": [
{
"name": "index_GroupKeyStateParent_parentChatRoomId",
"unique": false,
"columnNames": [
"parentChatRoomId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_GroupKeyStateParent_parentChatRoomId` ON `${TABLE_NAME}` (`parentChatRoomId`)"
}
],
"foreignKeys": [
{
"table": "GroupKeyState",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"chatRoomId"
],
"referencedColumns": [
"chatRoomId"
]
}
]
},
{
"tableName": "GroupSignedEvent",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `chatRoomId` TEXT NOT NULL, `publicKey` TEXT NOT NULL, `kind` INTEGER NOT NULL, `tags` TEXT NOT NULL, `content` TEXT NOT NULL, `signature` TEXT NOT NULL, `derivationPath` TEXT, `frostSigningSessionId` TEXT, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, `savedAt` INTEGER NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`chatRoomId`) REFERENCES `ChatRoom`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
@@ -2541,410 +2581,6 @@
}
]
},
{
"tableName": "MantraProject",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `publicKey` TEXT NOT NULL, `name` TEXT NOT NULL, `description` TEXT NOT NULL, `creatorPublicKey` TEXT NOT NULL, `ownerPublicKeys` TEXT NOT NULL, `chatRoomId` TEXT NOT NULL, `signature` TEXT NOT NULL, `relayHint` TEXT, `marmotGroupEventId` TEXT, `groupSignedEventId` TEXT, `nostrEventId` TEXT, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`chatRoomId`) REFERENCES `ChatRoom`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "publicKey",
"columnName": "publicKey",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "description",
"columnName": "description",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "creatorPublicKey",
"columnName": "creatorPublicKey",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "ownerPublicKeys",
"columnName": "ownerPublicKeys",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "chatRoomId",
"columnName": "chatRoomId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "signature",
"columnName": "signature",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "relayHint",
"columnName": "relayHint",
"affinity": "TEXT"
},
{
"fieldPath": "marmotGroupEventId",
"columnName": "marmotGroupEventId",
"affinity": "TEXT"
},
{
"fieldPath": "groupSignedEventId",
"columnName": "groupSignedEventId",
"affinity": "TEXT"
},
{
"fieldPath": "nostrEventId",
"columnName": "nostrEventId",
"affinity": "TEXT"
},
{
"fieldPath": "createdAt",
"columnName": "createdAt",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "updatedAt",
"columnName": "updatedAt",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
},
"indices": [
{
"name": "index_MantraProject_chatRoomId",
"unique": false,
"columnNames": [
"chatRoomId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_MantraProject_chatRoomId` ON `${TABLE_NAME}` (`chatRoomId`)"
}
],
"foreignKeys": [
{
"table": "ChatRoom",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"chatRoomId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "MantraProjectArtifactVersion",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `publicKey` TEXT NOT NULL, `projectId` TEXT NOT NULL, `artifactVersionId` TEXT NOT NULL, `chatRoomId` TEXT NOT NULL, `signature` TEXT NOT NULL, `relayHint` TEXT, `marmotGroupEventId` TEXT, `groupSignedEventId` TEXT, `nostrEventId` TEXT, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`projectId`) REFERENCES `MantraProject`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`artifactVersionId`) REFERENCES `MantraArtifactVersion`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`chatRoomId`) REFERENCES `ChatRoom`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "publicKey",
"columnName": "publicKey",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "projectId",
"columnName": "projectId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "artifactVersionId",
"columnName": "artifactVersionId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "chatRoomId",
"columnName": "chatRoomId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "signature",
"columnName": "signature",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "relayHint",
"columnName": "relayHint",
"affinity": "TEXT"
},
{
"fieldPath": "marmotGroupEventId",
"columnName": "marmotGroupEventId",
"affinity": "TEXT"
},
{
"fieldPath": "groupSignedEventId",
"columnName": "groupSignedEventId",
"affinity": "TEXT"
},
{
"fieldPath": "nostrEventId",
"columnName": "nostrEventId",
"affinity": "TEXT"
},
{
"fieldPath": "createdAt",
"columnName": "createdAt",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "updatedAt",
"columnName": "updatedAt",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
},
"indices": [
{
"name": "index_MantraProjectArtifactVersion_projectId",
"unique": false,
"columnNames": [
"projectId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_MantraProjectArtifactVersion_projectId` ON `${TABLE_NAME}` (`projectId`)"
},
{
"name": "index_MantraProjectArtifactVersion_artifactVersionId",
"unique": false,
"columnNames": [
"artifactVersionId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_MantraProjectArtifactVersion_artifactVersionId` ON `${TABLE_NAME}` (`artifactVersionId`)"
},
{
"name": "index_MantraProjectArtifactVersion_chatRoomId",
"unique": false,
"columnNames": [
"chatRoomId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_MantraProjectArtifactVersion_chatRoomId` ON `${TABLE_NAME}` (`chatRoomId`)"
}
],
"foreignKeys": [
{
"table": "MantraProject",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"projectId"
],
"referencedColumns": [
"id"
]
},
{
"table": "MantraArtifactVersion",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"artifactVersionId"
],
"referencedColumns": [
"id"
]
},
{
"table": "ChatRoom",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"chatRoomId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "MantraProjectTranslationArtifactVersion",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `publicKey` TEXT NOT NULL, `projectId` TEXT NOT NULL, `translationArtifactVersionId` TEXT NOT NULL, `chatRoomId` TEXT NOT NULL, `signature` TEXT NOT NULL, `relayHint` TEXT, `marmotGroupEventId` TEXT, `groupSignedEventId` TEXT, `nostrEventId` TEXT, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`projectId`) REFERENCES `MantraProject`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`translationArtifactVersionId`) REFERENCES `MantraTranslationArtifactVersion`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`chatRoomId`) REFERENCES `ChatRoom`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "publicKey",
"columnName": "publicKey",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "projectId",
"columnName": "projectId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "translationArtifactVersionId",
"columnName": "translationArtifactVersionId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "chatRoomId",
"columnName": "chatRoomId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "signature",
"columnName": "signature",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "relayHint",
"columnName": "relayHint",
"affinity": "TEXT"
},
{
"fieldPath": "marmotGroupEventId",
"columnName": "marmotGroupEventId",
"affinity": "TEXT"
},
{
"fieldPath": "groupSignedEventId",
"columnName": "groupSignedEventId",
"affinity": "TEXT"
},
{
"fieldPath": "nostrEventId",
"columnName": "nostrEventId",
"affinity": "TEXT"
},
{
"fieldPath": "createdAt",
"columnName": "createdAt",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "updatedAt",
"columnName": "updatedAt",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
},
"indices": [
{
"name": "index_MantraProjectTranslationArtifactVersion_projectId",
"unique": false,
"columnNames": [
"projectId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_MantraProjectTranslationArtifactVersion_projectId` ON `${TABLE_NAME}` (`projectId`)"
},
{
"name": "index_MantraProjectTranslationArtifactVersion_translationArtifactVersionId",
"unique": false,
"columnNames": [
"translationArtifactVersionId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_MantraProjectTranslationArtifactVersion_translationArtifactVersionId` ON `${TABLE_NAME}` (`translationArtifactVersionId`)"
},
{
"name": "index_MantraProjectTranslationArtifactVersion_chatRoomId",
"unique": false,
"columnNames": [
"chatRoomId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_MantraProjectTranslationArtifactVersion_chatRoomId` ON `${TABLE_NAME}` (`chatRoomId`)"
}
],
"foreignKeys": [
{
"table": "MantraProject",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"projectId"
],
"referencedColumns": [
"id"
]
},
{
"table": "MantraTranslationArtifactVersion",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"translationArtifactVersionId"
],
"referencedColumns": [
"id"
]
},
{
"table": "ChatRoom",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"chatRoomId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "MantraTranslation",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `publicKey` TEXT NOT NULL, `translationChunkId` TEXT NOT NULL, `translationArtifactVersionId` TEXT NOT NULL, `text` TEXT NOT NULL, `signature` TEXT NOT NULL, `chatRoomId` TEXT NOT NULL, `relayHint` TEXT, `marmotGroupEventId` TEXT, `groupSignedEventId` TEXT, `nostrEventId` TEXT, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`translationChunkId`) REFERENCES `MantraTranslationChunk`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`translationArtifactVersionId`) REFERENCES `MantraTranslationArtifactVersion`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`chatRoomId`) REFERENCES `ChatRoom`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
@@ -6096,7 +5732,7 @@
],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'ccbc98e82860c74663f3faed72cd1395')"
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'ff296ccd92cdb4bd61b3e150565f59c4')"
]
}
}
File diff suppressed because it is too large. Load diff