Generate SSD remote truth merge from typed Jerboa

ober

6cfe01b0e345622a69b5d9fc364447e6e6b0eb51

diff --git a/templates/ssd-review.ss b/templates/ssd-review.ss
index 0e4e135..ad7bab0 100644
--- a/templates/ssd-review.ss
+++ b/templates/ssd-review.ss
@@ -4827,6 +4827,7 @@
                 mainActivitySetPdfChoiceItems
                 mainActivityPullTruthDumpAsync
                 mainActivityPushTruthDumpAsync
+                mainActivityMergeRemoteTruthAsync
                 mainActivityInstallApproveAreaDialogButton
                 mainActivityInstallAppendDialogButton
                 mainActivityInstallEditDialogButtons
@@ -5335,6 +5336,12 @@
         (extern (mainActivityPdfUriRaw
                   (activity : MainActivity)) : (Nullable Uri)
           (kotlin-member-get pdfUri))
+        (extern (mainActivityLoadGenerationRaw
+                  (activity : MainActivity)) : Int32
+          (kotlin-member-get loadGeneration))
+        (extern (mainActivityPageIndexRaw
+                  (activity : MainActivity)) : Int32
+          (kotlin-member-get pageIndex))
         (extern (mainActivityCurrentSessionRaw
                   (activity : MainActivity)) : (Nullable SsdSession)
           (kotlin-member-get currentSession))
@@ -5412,6 +5419,14 @@
                   (payload : JSONObject)
                   (readTimeoutMillis : Int32)) : Unit
           (kotlin-member-call sendClientLog))
+        (extern (mainActivityLogDetectResultRaw
+                  (activity : MainActivity)
+                  (stage : String)
+                  (session : SsdSession)
+                  (detectorSource : String)
+                  (learnedGuesses : Int32)
+                  (ocrGuesses : Int32)) : Unit
+          (kotlin-member-call logDetectResult))
         (extern (mainActivityLoadPdfRaw
                   (activity : MainActivity)
                   (uri : Uri)
@@ -6851,10 +6866,58 @@
                     (mainActivityRunOnUiThreadRaw
                       activity
                       (lambda ()
-                        (mainActivitySetStatusRaw
-                          activity
-                          (truthPushFailedStatus
-                            (exceptionMessageRaw error)))))))))))
+                      (mainActivitySetStatusRaw
+                        activity
+                        (truthPushFailedStatus
+                          (exceptionMessageRaw error)))))))))))
+        (def (mainActivityMergeRemoteTruthAsync
+               (activity : MainActivity)
+               (view : SsdReviewView)
+               (store : TruthStore)
+               (session : SsdSession)
+               (generation : Int32)
+               (uri : Uri)
+               (page : Int32)) : Unit
+          (runBackground
+            (lambda ()
+              (let ((matches (truthStorePullRemoteTruthCount store session)))
+                (if (nonPositiveCount matches)
+                  (begin)
+                  (let ((truth (truthStoreLoadTruthForSession store session)))
+                    (if (truthPresent truth)
+                      (let ((merged (makeRemoteTruthMergeSession session)))
+                        (begin
+                          (copyLoadedTruthSsdArea
+                            merged
+                            (truthJsonObjectOrEmpty truth))
+                          (truthStoreApplyTruthAndPrune store merged)
+                          (mainActivityRunOnUiThreadRaw
+                            activity
+                            (lambda ()
+                              (if (currentLoadStale
+                                    generation
+                                    (mainActivityLoadGenerationRaw activity)
+                                    (mainActivityPdfUriRaw activity)
+                                    uri
+                                    (mainActivityPageIndexRaw activity)
+                                    page)
+                                (begin)
+                                (begin
+                                  (mainActivityShowSession activity view merged)
+                                  (reviewViewRefresh view)
+                                  (mainActivitySetStatusRaw
+                                    activity
+                                    (sessionCountsStatus
+                                      merged
+                                      ", pulled remote truth"))
+                                  (mainActivityLogDetectResultRaw
+                                    activity
+                                    "remote-truth"
+                                    merged
+                                    "remote-truth"
+                                    (int32 0)
+                                    (int32 0))))))))
+                      (begin))))))))
         (def (mainActivityInstallApproveAreaDialogButton
                (activity : MainActivity)
                (dialog : AlertDialog)
@@ -8904,23 +8967,7 @@
        "    }"
        ""
        "    private fun mergeRemoteTruthAsync(session: SsdSession, generation: Int, uri: Uri, page: Int) {"
-       "        thread {"
-       "            val matches = truthStorePullRemoteTruthCount(truthStore, session)"
-       "            if (nonPositiveCount(matches)) return@thread"
-       "            val truth = truthStoreLoadTruthForSession(truthStore, session)"
-       "            if (!truthPresent(truth)) return@thread"
-       "            val loadedTruth = truthJsonObjectOrEmpty(truth)"
-       "            val merged = makeRemoteTruthMergeSession(session)"
-       "            copyLoadedTruthSsdArea(merged, loadedTruth)"
-       "            truthStoreApplyTruthAndPrune(truthStore, merged)"
-       "            runOnUiThread {"
-       "                if (isStaleLoad(generation, uri, page)) return@runOnUiThread"
-       "                mainActivityShowSession(this, reviewView, merged)"
-       "                reviewViewRefresh(reviewView)"
-       "                setStatus(sessionCountsStatus(merged, \", pulled remote truth\"))"
-       "                logDetectResult(\"remote-truth\", merged, \"remote-truth\")"
-       "            }"
-       "        }"
+       "        mainActivityMergeRemoteTruthAsync(this, reviewView, truthStore, session, generation, uri, page)"
        "    }"
        ""
 	       "    private fun isCurrentLoad(generation: Int, uri: Uri, page: Int): Boolean ="
@@ -9604,7 +9651,7 @@
        "        mainActivityLogClientEventAsync(this, event, fields, CLIENT_LOG_READ_TIMEOUT_MS)"
        "    }"
        ""
-       "    private fun logDetectResult("
+       "    internal fun logDetectResult("
        "        stage: String,"
        "        session: SsdSession,"
        "        detectorSource: String,"