Move SSD truth group count to typed Kotlin

ober

7fba632f5c663e3c455e93da7afe7e40d11b0796

diff --git a/templates/ssd-review.ss b/templates/ssd-review.ss
index 578dc05..b9e4de0 100644
--- a/templates/ssd-review.ss
+++ b/templates/ssd-review.ss
@@ -1025,6 +1025,22 @@
                               (int32 0)))
                         payload))))))))))
 
+    (typed-kotlin-file "com/sfb/ssdreview/TruthJson.kt"
+      (kotlin-imports (org json JSONArray) (org json JSONObject))
+      (typed-library (com sfb ssdreview)
+        (export truthGroupCount)
+        (type JSONArray)
+        (type JSONObject)
+        (type Int32)
+        (def (truthJsonArrayOrEmpty (raw : (Nullable JSONArray))) : JSONArray
+          (if (nullable-null? raw)
+              (json-array-empty)
+              (nullable-get raw)))
+        (def (truthGroupCount (truth : JSONObject)) : Int32
+          (json-array-length
+            (truthJsonArrayOrEmpty
+              (json-object-opt-json-array truth "groups"))))))
+
     (typed-kotlin-file "com/sfb/ssdreview/Guess.kt"
       (typed-library (com sfb ssdreview)
         (export make-Guess Guess? Guess-label Guess-boxType Guess-reason)
@@ -5708,9 +5724,6 @@
        "        return remoteModified > 0L && remoteModified >= local.lastModified()"
        "    }"
        ""
-       "    private fun truthGroupCount(truth: JSONObject): Int ="
-       "        truth.optJSONArray(\"groups\")?.length() ?: 0"
-       ""
        "    private fun truthTime(truth: JSONObject): Long? ="
        "        jsonValueTime(truth.opt(\"generated_at\") ?: truth.opt(\"created_at\"))"
        ""