diff --git a/temerity/.env.vault b/temerity/.env.vault
index 25e8b67272661ad9921e0da0b2e78abcf851b6d9..48fd5a7e153b47644a92dc6052842e4102caf227 100644
--- a/temerity/.env.vault
+++ b/temerity/.env.vault
@@ -4,8 +4,8 @@
 #/--------------------------------------------------/
 
 # development
-DOTENV_VAULT_DEVELOPMENT="DCHgKIC5D+Tef2A5UpGbSV6legsP/JCF7fUpqRdMwFsKbMst7VDmKDo4oLOvRCCgJl6ADvCm9oI2B79zntB1K5zRFo7TTbBtw9Vova+6X5BpoA7YYsf5N44aYKwsWqkRp6JD0p4VO0arpX1XWNjmK1LG2UPsfUU3gLu2I7plsYtSi4YRhNSh2gHccQCgC6FmQS9CG8KoQQFikW72DYmIMNALDq5xxKG2DgfRYTBER+qPwFAg7IQACIt/N4L9LEsrcnE1xFoPgwlLXUzLHlYpQpvfkg6V7brGobbcvUwf0+YsDHGFf48y9CGAOIlUYk9TgXyxi9T4Fa/bSwm+vLUDK7Mo26FI+8HIyaPgramA8X2+o6k73ULUfF8DAD2JiC5AWe42CSGaZAwCe0XILX/7iS4NTHnmX1Fx/zRAMxDZmPd0BTm9Mw9cXxtk1zeDAo37EUqKpztwMQ7PbMNjLeDzy/5DNAlO6Ke9u2RoUsphpolS6vm4Lnuheo9BlAk3N8inAzdPG8NMPhCfTmy1GmiseQtsUUdP4QtFRJtBSqJ2BBNTkD8bmwPWBdePM/w1jyLQhg4TRSpQtMydCJKt/WqqSzXq7JQJDz+9T3yH+snH8xiac/nQAvxocEw/CmA4kYsXsvYgFR7FgBTBW1ugcldfHx88eFZyPfJ/T9z0+IVovlTSUDOlWgFV8i4DbTUzYEu3mnoVTr2j98z0qzhpYu50MLl34ZtGVzQAuVWGmGvr+xueGQWhBzhKlPnNAmi5WEnnOY+ysnMaP+bIWHLbRmKyvWdRrxX8xySOEgsn7oH0mQZwWZZuYlHHGwT5CSSqe/LBNPTmSmOC6ZCj5Gf2q2dgCri1rzyyd2Ny7sI/22lB5WE1c7ltdxaVGtTHFt7wOrOrzAaklF4TlJD0gonje6ii+V7di/sn5uVbhpxvjbfnhWt82VYFK1F6Zr0xYwIjSehs7YUnlSLgsUzaWt6E/HbBB+3/M/0="
-DOTENV_VAULT_DEVELOPMENT_VERSION=20
+DOTENV_VAULT_DEVELOPMENT="ObnbpxIJgixKNbmk/oQmohcTxUbFL8RxERUxAo5WB4cCif7LZobiRAfZhutEygQosdaWcGkblPYs+IOZsBaX26BY9Y4gOCzuUQWRPR9l9a7ml6Qt2M0ilZUO2gOXjpJ1GHueYye4aOgi0HlFNlguxIKllCNncBebiQSdyxQcRVUvFncDmLrJavuse0LpCdfD1g31mOD2pzxwptUwPKYg7BG1dDdO5639pBAzrAwMho0yYYS2R6c578n1yepPgg5WV6nqWOqqHRc2/pcz2GwBZEwFeZwrciYKIAA28E5TBoM/ZcHHIIPdZn1M3ejFX8Sp5oSvT78YPcMCiX3Dpq+R9Gsl9FHVgJZAQAaMD4Dwrmu7tT7OWgF2v2PJBRnDRz1g7b1duC1eVKsa3SHTVr4bRHioLdRakzwkcSCxNndBPGndMXDeKTKJY8OHbgA1JyoTf21Wh5mhkQvhHrMr+1IzubSGoz5Z5zgjilNtBQOTSLZxG4YK/mA7v5o5x9RJ8ce3N//OZgTHpDC/2n8QmhQpZsqr9A1rB4o87WCGoklZfQTturDayqoXWNIHmlJ+WDdtAyDsLYu9eQdHOlh4GZY94kNRMtwVicbTLevr7pvc5aY/PIwu8kgpAD4UL96b75J3UZ0u4kzaczoS837bCnFlxgPTkFs0G2oZx975pNJSuwyyvRk5/ADskKZgW5gxF0kAcO7h/+GKPLhZOXm50peNaQbJjabT/e7x3jR7rrCVFwEQloovWL7/lHklze9kntrIuBB704by74KfqYCV/RIVukSkazrwU6KY3EyswU1N8yj8g3wzd5V7LUnaFX1pqijtc7mUr30piM/DHALTJfAfYa2KQwzuIJ1egJhCT5kWSv7wKyMtGvNcZrNIYS8pkk9pqsW/YJ2JDwqJFh9/f32nk0Oj4LQk19j0DNdmu4QRdmeRrVx/pEPl24s8GPzQGoUly6N14psmIH0luV7yY+QU0NAU0ho="
+DOTENV_VAULT_DEVELOPMENT_VERSION=21
 
 # ci
 DOTENV_VAULT_CI="n69uhs4m6qCfBKFNpDoqnpPfqeXrU+T3VIO+eseGVKWbRjZhRxx3VqAqq1P5Pml/YNJSR3t7N48cOQEhQdEvgwgIceG6DtJClkHZy712jhivwt6CVF7Hi0znBM9G0mub/guVwTUngFBRsQKw3XpDnxrzfo/FUPP09Zhy3D604wDnKuk/M6cUgT4o3jucOXmsjnwZTm/UUz+65eRSB0L5O8Gy7tB1e30eH5WUmx+hnG85v9+QENjt1inU9bZuefwnf7XzSaPKisVZVm4AYxXWnGIVP84Wy2O2h5nytLPdw2Z72mwaGSTRp0miUtUynTtFsm/SeoIOAgbixm7ScF4o/juwfq6IhVUBDfZStjXMx/150U2QZVbseVHKWrIdpPy9bZ7gO2ufMDps+daXWsJsHRqe11UTPhyZ8jA5V0oxDHe1y1cf0Dr9ZUr0g4E="
diff --git a/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/DevDeviceApiTests.kt b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/DevDeviceApiTests.kt
index 058672e8279d74875a658994c3975424e65c6dbb..efec7524c820719f11fafb4a3f51598cb40545d1 100644
--- a/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/DevDeviceApiTests.kt
+++ b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/DevDeviceApiTests.kt
@@ -18,27 +18,23 @@
 package edu.ucsc.its.temerity.test
 
 import edu.ucsc.its.temerity.core.Temerity
-import io.kotest.core.spec.style.FunSpec
 import kotlinx.coroutines.runBlocking
 
-class DevDeviceApiTests :
-  FunSpec({
-    val dotenv = dotenvVaultJvm()
-
-    lateinit var temerityTest: Temerity
-
+private class DevDeviceApiTests : TemerityFunSpec() {
+  init {
     beforeTest {
-      temerityTest = Temerity {
+      testTemerity = Temerity {
         configureDevEnvironment(dotenv)
       }
     }
 
     test("4.2.1 - PlatformClient can fetch a list of devices") {
       runBlocking {
-        val returnedDevices = temerityTest.getDevices()
+        val returnedDevices = testTemerity.getDevices()
         println("Returned devices:")
         returnedDevices.forEach { println(it) }
         assert(returnedDevices.isNotEmpty())
       }
     }
-  })
+  }
+}
diff --git a/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/DevGroupApiTests.kt b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/DevGroupApiTests.kt
index 3658f2465eaef2f5dc443af31816e9b5143d2296..521acc2a60bb99349dfffc7102a1e740e8bb94f8 100644
--- a/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/DevGroupApiTests.kt
+++ b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/DevGroupApiTests.kt
@@ -18,16 +18,10 @@
 package edu.ucsc.its.temerity.test
 
 import edu.ucsc.its.temerity.core.Temerity
-import io.kotest.core.spec.style.FunSpec
 import kotlinx.coroutines.runBlocking
 
-class DevGroupApiTests :
-  FunSpec({
-
-    val dotenv = dotenvVaultJvm()
-
-    lateinit var testTemerity: Temerity
-
+private class DevGroupApiTests : TemerityFunSpec() {
+  init {
     beforeTest {
       testTemerity = Temerity {
         configureDevEnvironment(dotenv)
@@ -42,4 +36,5 @@ class DevGroupApiTests :
         assert(returnedGroups.isNotEmpty())
       }
     }
-  })
+  }
+}
diff --git a/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/DevUserApiTests.kt b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/DevUserApiTests.kt
index 57ac043bbcff13f64448a341ebe7edf68855b45a..43885a0c174e9dabb24a2fffc3bb777ff28d2e0e 100644
--- a/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/DevUserApiTests.kt
+++ b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/DevUserApiTests.kt
@@ -21,21 +21,18 @@ import co.touchlab.kermit.Logger
 import com.skydoves.sandwich.StatusCode
 import com.skydoves.sandwich.ktor.getStatusCode
 import edu.ucsc.its.temerity.core.Temerity
-import edu.ucsc.its.temerity.core.Temerity.Companion.createLogger
 import edu.ucsc.its.temerity.model.NewUser
 import edu.ucsc.its.temerity.model.UserUpdate
-import io.kotest.core.spec.style.FunSpec
+import io.kotest.common.ExperimentalKotest
 import io.kotest.matchers.shouldBe
 import io.ktor.http.HttpStatusCode
 import kotlinx.coroutines.runBlocking
 
-class DevUserApiTests :
-  FunSpec({
+private class DevUserApiTests : TemerityFunSpec() {
+  init {
+    @OptIn(ExperimentalKotest::class)
+    blockingTest = true
 
-    val dotenv = dotenvVaultJvm()
-    val kermit = createLogger(tag = "DevUserApiTests")
-
-    lateinit var testTemerity: Temerity
     beforeTest {
       testTemerity = Temerity {
         configureDevEnvironment(dotenv)
@@ -141,4 +138,5 @@ class DevUserApiTests :
         }
       }
     }
-  })
+  }
+}
diff --git a/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/DevUtilityTests.kt b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/DevUtilityTests.kt
index 19a62a3a5572b022f7f77feddacdf38692e2b5a7..aa3e10bdf99fe3a9071122dffa4839d8bd57ed9b 100644
--- a/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/DevUtilityTests.kt
+++ b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/DevUtilityTests.kt
@@ -18,25 +18,16 @@
 package edu.ucsc.its.temerity.test
 
 import edu.ucsc.its.temerity.core.Temerity
-import edu.ucsc.its.temerity.core.Temerity.Companion.createLogger
-import io.kotest.core.spec.style.FunSpec
+import io.kotest.common.ExperimentalKotest
 import io.kotest.engine.runBlocking
-import org.koin.test.KoinTest
 import kotlin.time.Duration.Companion.hours
 import kotlin.time.Duration.Companion.minutes
 
-class DevUtilityTests :
-  FunSpec(),
-  KoinTest {
-
-  private val kermit = createLogger("DevUtilityTests")
+private class DevUtilityTests : TemerityFunSpec() {
 
   init {
-    coroutineDebugProbes = true
-
-    val dotenv = dotenvVaultJvm()
-
-    lateinit var testTemerity: Temerity
+    @OptIn(ExperimentalKotest::class)
+    blockingTest = true
 
     beforeTest {
       testTemerity = Temerity {
diff --git a/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/ModelTests.kt b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/ModelTests.kt
index 998583d244ab91c5860a32b74e7cc600e8094c6b..cec8e213c84032918802ac2e63629c41aa607c97 100644
--- a/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/ModelTests.kt
+++ b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/ModelTests.kt
@@ -18,14 +18,19 @@
 package edu.ucsc.its.temerity.test
 
 import edu.ucsc.its.temerity.model.EventType
-import io.kotest.core.spec.style.FunSpec
+import io.kotest.common.ExperimentalKotest
+
+private class ModelTests : TemerityFunSpec() {
+
+  init {
+    @OptIn(ExperimentalKotest::class)
+    blockingTest = true
 
-class ModelTests :
-  FunSpec({
     test("Return enum AuditLog EventTypes in alphabetical order") {
       val sortedEventTypes = EventType.entries.sortedBy { it.value }
       sortedEventTypes.forEach {
         println(it.value)
       }
     }
-  })
+  }
+}
diff --git a/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/ProdReportTests.kt b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/ProdReportTests.kt
index 5ce6590495267cbee21e8aa098b035297fe23dbd..9589c8b017e9964c2fd66982fdc5d5f256efb1c9 100644
--- a/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/ProdReportTests.kt
+++ b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/ProdReportTests.kt
@@ -19,8 +19,6 @@ package edu.ucsc.its.temerity.test
 
 import edu.ucsc.its.temerity.AuditLogSortOrder.NEW_FIRST
 import edu.ucsc.its.temerity.core.Temerity
-import edu.ucsc.its.temerity.core.Temerity.Companion.createLogger
-import edu.ucsc.its.temerity.core.Temerity.Companion.currentDate
 import edu.ucsc.its.temerity.model.EventType.AUTOMATED_SESSION_FAILED_TO_START
 import edu.ucsc.its.temerity.model.EventType.AUTOMATED_SESSION_MONITOR
 import edu.ucsc.its.temerity.model.EventType.CAPTURE_ERROR
@@ -32,7 +30,8 @@ import edu.ucsc.its.temerity.model.EventType.HDCP_SIGNAL_DETECTED
 import edu.ucsc.its.temerity.model.EventType.HUB_CAPTURE_PROBLEM
 import edu.ucsc.its.temerity.model.EventType.NEW_LOG_IN
 import edu.ucsc.its.temerity.model.EventType.RECORDING_ERROR
-import io.kotest.core.spec.style.FunSpec
+import edu.ucsc.its.temerity.util.currentDate
+import io.kotest.common.ExperimentalKotest
 import io.kotest.matchers.file.shouldNotBeEmpty
 import kotlinx.coroutines.runBlocking
 import kotlinx.datetime.Clock
@@ -42,26 +41,18 @@ import kotlinx.datetime.minus
 import kotlinx.datetime.todayIn
 import org.jetbrains.kotlinx.dataframe.api.toDataFrame
 import org.jetbrains.kotlinx.dataframe.io.writeCSV
-import org.koin.test.KoinTest
 import java.io.File
 import kotlin.time.Duration.Companion.minutes
 import kotlin.uuid.ExperimentalUuidApi
 import kotlin.uuid.Uuid
-import co.touchlab.kermit.Logger as KermitLogger
 
 @OptIn(ExperimentalUuidApi::class)
-class ProdReportTests :
-  FunSpec(),
-  KoinTest {
-
-  private val kermit: KermitLogger = createLogger(tag = "TemerityDevTest")
+private class ProdReportTests : TemerityFunSpec() {
 
   init {
-    coroutineDebugProbes = true
-
-    val dotenv = dotenvVaultJvm()
+    @OptIn(ExperimentalKotest::class)
+    blockingTest = true
 
-    lateinit var testTemerity: Temerity
     val today = currentDate()
 
     beforeTest {
@@ -176,23 +167,23 @@ class ProdReportTests :
       }
     }
 
-    // "Mislinked" YuJa course group report
-    // Generate Report listing all groups matching specific sis id that have the wrong term code, or are duplicates
-    test("PlatformClient can fetch a list of groups with specific SIS ID by term and verifying term code matches") {
+    // "Mislinked" YuJa course report
+    // Generate Report listing all courses matching specific sis id that have the wrong term code, or are duplicates
+    test("PlatformClient can fetch a list of courses with specific SIS ID by term and verify that the term code matches the correct one for the quarter") {
       runBlocking {
         val fullCoursesList = testTemerity.getCourses()
         val invalidGroupTerm = fullCoursesList.filter {
-          it.sisId.startsWith("2248")
+          it.sisId.startsWith("2250")
         }.filter {
-          it.courseTerm != "2024 Fall Quarter"
+          it.courseTerm != "2025 Winter Quarter"
         }
         val nonMatchingSisId = fullCoursesList.filter {
-          it.courseTerm == "2024 Fall Quarter"
+          it.courseTerm == "2025 Winter Quarter"
         }.filter {
-          !it.sisId.startsWith("2248")
+          !it.sisId.startsWith("2250")
         }
         val duplicateSisId = fullCoursesList.filter {
-          it.sisId.startsWith("2248")
+          it.sisId.startsWith("2250")
         }.groupBy { it.sisId }.filter { it.value.size > 1 }.values.flatten()
         val problemCourses = invalidGroupTerm + nonMatchingSisId + duplicateSisId
         println("Total returned groups count: ${problemCourses.size}")
diff --git a/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/ProdUtilityTests.kt b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/ProdUtilityTests.kt
index 6e43ac6f5bd8bb39733c6c4f378454d9876b6c16..632ec391b6437708d66aeb8e13061be3e9c6426d 100644
--- a/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/ProdUtilityTests.kt
+++ b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/ProdUtilityTests.kt
@@ -18,29 +18,17 @@
 package edu.ucsc.its.temerity.test
 
 import edu.ucsc.its.temerity.core.Temerity
-import edu.ucsc.its.temerity.core.Temerity.Companion.createLogger
 import io.kotest.common.ExperimentalKotest
-import io.kotest.core.spec.style.FunSpec
 import io.kotest.engine.runBlocking
-import org.koin.test.KoinTest
 import kotlin.time.Duration.Companion.hours
 import kotlin.time.Duration.Companion.minutes
 
-class ProdUtilityTests :
-  FunSpec(),
-  KoinTest {
-
-  private val kermit = createLogger("ProdUtilityTests")
+private class ProdUtilityTests : TemerityFunSpec() {
 
   init {
-    coroutineDebugProbes = true
     @OptIn(ExperimentalKotest::class)
     blockingTest = true
 
-    val dotenv = dotenvVaultJvm()
-
-    lateinit var testTemerity: Temerity
-
     beforeTest {
       testTemerity = Temerity {
         configureProdEnvironment(dotenv)
diff --git a/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/TemerityDevTest.kt b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/TemerityDevTest.kt
index 51fd825ba227df0925ac95ba04aa83696f9dbf26..dd216fc4d88704d0742311d2397f67286a3302c7 100644
--- a/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/TemerityDevTest.kt
+++ b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/TemerityDevTest.kt
@@ -22,12 +22,12 @@ import com.skydoves.sandwich.StatusCode
 import com.skydoves.sandwich.ktor.getStatusCode
 import edu.ucsc.its.temerity.AuditLogSortOrder.NEW_FIRST
 import edu.ucsc.its.temerity.core.Temerity
-import edu.ucsc.its.temerity.core.Temerity.Companion.currentDate
 import edu.ucsc.its.temerity.model.EventType.NEW_LOG_IN
 import edu.ucsc.its.temerity.model.NewUser
+import edu.ucsc.its.temerity.util.currentDate
 import io.github.z4kn4fein.semver.Version
 import io.github.z4kn4fein.semver.toVersion
-import io.kotest.core.spec.style.FunSpec
+import io.kotest.common.ExperimentalKotest
 import io.kotest.matchers.file.shouldNotBeEmpty
 import io.kotest.matchers.shouldBe
 import kotlinx.coroutines.runBlocking
@@ -42,20 +42,15 @@ import kotlin.uuid.ExperimentalUuidApi
 import kotlin.uuid.Uuid
 
 @OptIn(ExperimentalUuidApi::class)
-class TemerityDevTest : FunSpec() {
-
-  private lateinit var kermit: Logger
-
+private class TemerityDevTest : TemerityFunSpec() {
   init {
-    val dotenv = dotenvVaultJvm()
-
-    lateinit var testTemerity: Temerity
+    @OptIn(ExperimentalKotest::class)
+    blockingTest = true
 
     beforeTest {
       testTemerity = Temerity {
         configureDevEnvironment(dotenv)
       }
-      kermit = Temerity.createLogger("TemerityDevTest")
     }
 
     test("Temerity client returns a correctly-formatted version String") {
diff --git a/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/Util.kt b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/Util.kt
index 1f0e87313894ddac9d6c2ceb8b4a9bad9e8166cc..299c20b2fa6bc737fe5c8a424bff81f6d6256db8 100644
--- a/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/Util.kt
+++ b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/Util.kt
@@ -18,10 +18,13 @@
 package edu.ucsc.its.temerity.test
 
 import edu.ucsc.its.temerity.TemClientConfig
+import edu.ucsc.its.temerity.core.Temerity
+import edu.ucsc.its.temerity.core.Temerity.Companion.createLogger
 import io.github.cdimascio.dotenv.Configuration
 import io.github.cdimascio.dotenv.Dotenv
 import io.github.cdimascio.dotenv.dotenv
 import io.kotest.core.extensions.TestCaseExtension
+import io.kotest.core.spec.style.FunSpec
 import io.kotest.core.test.TestCase
 import io.kotest.core.test.TestResult
 import io.kotest.core.test.TestType
@@ -31,6 +34,7 @@ import org.koin.core.context.stopKoin
 import org.koin.core.module.Module
 import org.koin.test.mock.MockProvider
 import org.koin.test.mock.Provider
+import co.touchlab.kermit.Logger as KermitLogger
 
 // Utility function from: https://github.com/alvr/katana/blob/d10a53486b95bbc2cfaa0fed636b913957334366/core/tests/src/commonMain/kotlin/dev/alvr/katana/core/tests/KoinExtension.kt
 // Originally based on kotest koin extension: https://github.com/kotest/kotest-extensions-koin/blob/30bc2867dd3adfe4e3dc164f97031146563d4435/src/commonMain/kotlin/io.kotest.koin/KoinExtension.kt
@@ -94,3 +98,9 @@ fun dotenvVaultJvm(block: (Configuration.() -> Unit)? = null): Dotenv = when (bl
     block()
   }
 }
+
+internal abstract class TemerityFunSpec : FunSpec() {
+  internal val dotenv: Dotenv = dotenvVaultJvm()
+  internal val kermit: KermitLogger = createLogger()
+  internal lateinit var testTemerity: Temerity
+}