Move SSD component helpers to typed Kotlin

ober

ef30e4c6c0ca69b9aac0dc68c7eba0c6b3c20a02

diff --git a/.build.yml b/.build.yml
index d0f3e11..746501a 100644
--- a/.build.yml
+++ b/.build.yml
@@ -5,7 +5,7 @@ packages:
   - make=4.4.1-r4
 sources:
   # Build dependency: full immutable commit, mirrored in dependencies.lock.json.
-  - "https://git.sr.ht/~lisp/jerboa#5f11ec65196844516307d5196364331364295a9c"
+  - "https://git.sr.ht/~lisp/jerboa#c6083df15cb3007c6bb5c19cfc581d35bd12e8d3"
   # The second source is the build subject selected by the SourceHut submitter.
   - https://git.sr.ht/~lisp/jerboa-android
 tasks:
@@ -14,6 +14,6 @@ tasks:
       test "$(apk info -v chez-scheme)" = chez-scheme-10.3.0-r2
       test "$(apk info -v git)" = git-2.54.0-r0
       test "$(apk info -v make)" = make-4.4.1-r4
-      test "$(git -C ../jerboa rev-parse HEAD)" = 5f11ec65196844516307d5196364331364295a9c
-      test "$(git -C ../jerboa rev-parse 'HEAD^{tree}')" = b07a69be351dbe1d44f0fd4b74c0af522f071f17
+      test "$(git -C ../jerboa rev-parse HEAD)" = c6083df15cb3007c6bb5c19cfc581d35bd12e8d3
+      test "$(git -C ../jerboa rev-parse 'HEAD^{tree}')" = d2b91c54afd251ec16459845f91613539016297d
       JERBOA="chez --libdirs .:../jerboa/lib --script" make test
diff --git a/dependencies.lock.json b/dependencies.lock.json
index 1b0c270..31561d1 100644
--- a/dependencies.lock.json
+++ b/dependencies.lock.json
@@ -11,8 +11,8 @@
   "generator_runtime": {
     "name": "jerboa",
     "repository": "https://git.sr.ht/~lisp/jerboa",
-    "commit": "5f11ec65196844516307d5196364331364295a9c",
-    "tree": "b07a69be351dbe1d44f0fd4b74c0af522f071f17"
+    "commit": "c6083df15cb3007c6bb5c19cfc581d35bd12e8d3",
+    "tree": "d2b91c54afd251ec16459845f91613539016297d"
   },
   "assurance_tools": {
     "osv_scanner": {
diff --git a/full-kotlin.md b/full-kotlin.md
index 3656167..6d59be1 100644
--- a/full-kotlin.md
+++ b/full-kotlin.md
@@ -43,7 +43,7 @@ The vendored Jerboa tree already has the right starting point:
 
 Do not fork that model inside `jandroid.ss`. General Kotlin backend work belongs in Jerboa. Android project and Android DSL work belongs in `jerboa-android`.
 
-Version caveat: this repository now pins Jerboa commit `5f11ec65196844516307d5196364331364295a9c`, tree `b07a69be351dbe1d44f0fd4b74c0af522f071f17`. Before editing compiler APIs, check out the exact pinned commit (or the intended replacement commit), rerun the typed parser/checker/core inventory, and record any differences. Do not assume two Jerboa snapshots expose identical IR.
+Version caveat: this repository now pins Jerboa commit `c6083df15cb3007c6bb5c19cfc581d35bd12e8d3`, tree `d2b91c54afd251ec16459845f91613539016297d`. Before editing compiler APIs, check out the exact pinned commit (or the intended replacement commit), rerun the typed parser/checker/core inventory, and record any differences. Do not assume two Jerboa snapshots expose identical IR.
 
 ### 2.3 `~/sfb` source requirements
 
diff --git a/scripts/verify-supply-chain.sh b/scripts/verify-supply-chain.sh
index f6ac140..68dd68e 100755
--- a/scripts/verify-supply-chain.sh
+++ b/scripts/verify-supply-chain.sh
@@ -3,8 +3,8 @@ set -eu
 
 repo=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd -P)
 lock="$repo/dependencies.lock.json"
-jerboa_commit=5f11ec65196844516307d5196364331364295a9c # gitsafe:ignore
-jerboa_tree=b07a69be351dbe1d44f0fd4b74c0af522f071f17 # gitsafe:ignore
+jerboa_commit=c6083df15cb3007c6bb5c19cfc581d35bd12e8d3 # gitsafe:ignore
+jerboa_tree=d2b91c54afd251ec16459845f91613539016297d # gitsafe:ignore
 gradle_sha=20f1b1176237254a6fc204d8434196fa11a4cfb387567519c61556e8710aed78
 jdk_macos_sha=8fa1eff40bb637a33613b2ccb8b12c70dc3661cc22cf8e784943715769a05336
 jdk_linux_sha=d8afc263758141a66e0e3aafc321e783f7016696f4eaea067d340a269037d331
diff --git a/templates/ssd-review.ss b/templates/ssd-review.ss
index 5c0ae12..16ac25a 100644
--- a/templates/ssd-review.ss
+++ b/templates/ssd-review.ss
@@ -102,7 +102,8 @@
                 Component-x2 Component-x2-set!
                 Component-y2 Component-y2-set!
                 Component-area Component-area-set!
-                Component-detector)
+                Component-detector
+                componentW componentH componentAdd)
         (type Int32)
         (record Component
           ((mut x1 : Int32)
@@ -110,7 +111,27 @@
            (mut x2 : Int32)
            (mut y2 : Int32)
            (mut area : Int32)
-           (detector : String)))))
+           (detector : String)))
+        (def (componentW (component : Component)) : Int32
+          (+ (- (Component-x2 component)
+                (Component-x1 component))
+             (int32 1)))
+        (def (componentH (component : Component)) : Int32
+          (+ (- (Component-y2 component)
+                (Component-y1 component))
+             (int32 1)))
+        (def (componentAdd (component : Component) (x : Int32) (y : Int32)) : Unit
+          (begin
+            (Component-x1-set! component
+              (if (< x (Component-x1 component)) x (Component-x1 component)))
+            (Component-y1-set! component
+              (if (< y (Component-y1 component)) y (Component-y1 component)))
+            (Component-x2-set! component
+              (if (> x (Component-x2 component)) x (Component-x2 component)))
+            (Component-y2-set! component
+              (if (> y (Component-y2 component)) y (Component-y2 component)))
+            (Component-area-set! component
+              (+ (Component-area component) (int32 1)))))))
 
     (typed-kotlin-file "com/sfb/ssdreview/SsdGroup.kt"
       (typed-library (com sfb ssdreview)
@@ -2450,18 +2471,6 @@
        "import kotlin.math.min"
        "import kotlin.math.roundToInt"
        ""
-       "private fun componentW(component: Component): Int = component.x2 - component.x1 + 1"
-       ""
-       "private fun componentH(component: Component): Int = component.y2 - component.y1 + 1"
-       ""
-       "private fun componentAdd(component: Component, x: Int, y: Int) {"
-       "    component.x1 = min(component.x1, x)"
-       "    component.y1 = min(component.y1, y)"
-       "    component.x2 = max(component.x2, x)"
-       "    component.y2 = max(component.y2, y)"
-       "    component.area += 1"
-       "}"
-       ""
        "object SsdDetector {"
        "    fun detectCells(bitmap: Bitmap): MutableList<SsdCell> {"
        "        val width = bitmap.width"