Move SSD remote write decision to typed Kotlin

ober

069b2c8065d1271a6069d4a25b92fccacac59dd4

diff --git a/templates/ssd-review.ss b/templates/ssd-review.ss
index 9ae91eb..0a4f3de 100644
--- a/templates/ssd-review.ss
+++ b/templates/ssd-review.ss
@@ -1586,7 +1586,8 @@
                 remoteBearerTokenPresent remoteBearerTokenValid
                 remotePinPresent remotePinOrNull remotePinSha256Length
                 remoteRelativePathSafe
-                shouldCompareMoreCompleteTruth shouldReplaceLocalByTimes
+                shouldCompareMoreCompleteTruth shouldWriteRemoteTruth
+                shouldReplaceLocalByTimes
                 zipEntryIsDirectory zipEntryDeclaresExcessiveSize)
         (type File)
         (type Path)
@@ -1726,6 +1727,13 @@
         (def (shouldCompareMoreCompleteTruth (replaceIfMoreComplete : Bool)
                                              (destination : File)) : Bool
           (and replaceIfMoreComplete (fileExists destination)))
+        (def (shouldWriteRemoteTruth (compareMoreComplete : Bool)
+                                     (remoteGroupCount : Int32)
+                                     (localGroupCount : Int32)
+                                     (localPolicyAllows : Bool)) : Bool
+          (if compareMoreComplete
+            (or (>= remoteGroupCount localGroupCount) localPolicyAllows)
+            localPolicyAllows))
         (def (shouldReplaceLocalByTimes (localGenerated : (Nullable Int))
                                         (remoteGenerated : (Nullable Int))
                                         (remoteModified : Int)
@@ -8351,12 +8359,9 @@
        "        val key = validatedSourceKey(truthSourceKey(truth)) ?: return false"
        "        val dest = truthPath(key)"
        "        val text = truth.toString(2)"
-       "        val shouldWrite = if (shouldCompareMoreCompleteTruth(replaceIfMoreComplete, dest)) {"
-       "            val local = jsonObjectFromText(readLocalText(dest))"
-       "            truthGroupCount(truth) >= truthGroupCount(local) || shouldReplaceLocal(dest, text, modified)"
-       "        } else {"
-       "            shouldReplaceLocal(dest, text, modified)"
-       "        }"
+       "        val compareMoreComplete = shouldCompareMoreCompleteTruth(replaceIfMoreComplete, dest)"
+       "        val local = if (compareMoreComplete) jsonObjectFromText(readLocalText(dest)) else null"
+       "        val shouldWrite = shouldWriteRemoteTruth(compareMoreComplete, truthGroupCount(truth), nullableTruthGroupCount(local), shouldReplaceLocal(dest, text, modified))"
        "        if (!shouldWrite) return false"
        "        atomicWriteText(dest, text)"
        "        invalidateTruthIndex()"