kotlin — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited kotlin (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Use this skill for Kotlin code that needs strong type modeling, explicit async boundaries, and idiomatic Android integration. When the code is part of a Nitro Module, pair this with build-nitro-modules for generated specs, Promise mapping, annotations, and HybridObject constraints.
barcode and barcodeType must exist together, put them on ScannedBarcode.// Avoid: related fields are nullable and the valid combinations are implicit.
data class ScannedData(
val position: Point,
val text: String?,
val barcode: String?,
val barcodeType: BarcodeType?,
val face: Rect?,
)
// Prefer: each variant exposes only the fields that are valid for it.
sealed interface ScannedData {
val position: Point
}
data class ScannedText(
override val position: Point,
val text: String,
) : ScannedData
data class ScannedBarcode(
override val position: Point,
val barcode: String,
val barcodeType: BarcodeType,
) : ScannedData
data class ScannedFace(
override val position: Point,
val face: Rect,
) : ScannedDataPromise.parallel for CPU-bound synchronous work that should not run on the caller thread.runBlocking in library code, property getters, setters, or JS-facing entry points.Promise<T> method.launch, withContext, dispatcher, handler, or executor hops as an architecture smell. A component should either own the coroutine scope/dispatcher/lifecycle it works on, or cross into that owner once at the public async boundary or native callback boundary.delay, Thread.sleep, Handler.postDelayed, timers, extra dispatcher hops, or calling the same method twice. Fix the owner dispatcher/lifecycle, state machine, callback/event, Flow, or async API boundary instead. Retry only for external nondeterminism such as hardware, OS services, remote services, or network, and keep retries bounded, cancellable, and idempotent.Mutex, synchronized, and ReentrantLock as last-resort synchronization, not default listener or callback plumbing. Before adding one, identify the exact shared mutable values, concurrent callers, and why a single owner dispatcher/lifecycle, channel/Flow, or immutable snapshot is not enough.val and var for cheap in-memory state or derived values.// Avoid: blocking work hidden in a getter.
val status: SessionStatus
get() = runBlocking { session.status() }
// Prefer: make the async boundary explicit.
fun getStatus(): Promise<SessionStatus> {
return Promise.async {
session.status()
}
}open; keep them that way unless inheritance is intentional.data class for plain values and regular classes for owned resources or lifecycle.sealed interface or sealed class for closed result families.require, check, or specific exceptions for invalid inputs and invalid state. Do not silently no-op user-reachable failures.!! except at narrow boundaries where a prior check makes the invariant obvious. Prefer early returns, requireNotNull, or typed state.return statements inside multi-line control flow. Do not lift the return outside a multi-line try/catch, if, when, or lambda just to make it expression-like; use try { return value } catch (...) { return fallback }.return@map value for the result. Omit the label only for true single-expression lambdas like items.map { it.toString() }; do not write items.map { return@map it.toString() }.formats.map { it.toMLKitFormat() }, not a multi-line map { format -> format.toMLKitFormat() }. Do not use it when a surrounding or nested lambda already uses it; name parameters in nested lambdas or when clarity needs it.HybridDataScanner.kt should implement HybridDataScanner; it should not also contain Android helpers, geometry conversions, listeners, or extension utilities.Barcode+toScannedCode.kt, TargetBarcodeFormat+toMLKitFormat.kt, and BarcodeFormat+fromMLKitBarcodeFormat.kt with internal visibility where appropriate.fun, val, or var declarations inside Hybrid* implementation files or other primary implementation files, even when they are private, tiny, or only used by that file. Put every extension in a separate named Type+operation.kt extension/converter file so code splitting, maintainability, and future diffs stay clean.Hybrid* factories and implementation methods. Permission checks, manifest feature/permission validation, PackageManager capability checks, service availability checks, and similar setup guards belong in focused helper files; the HybridObject call site should stay one or two lines.Utils.kt files for these helpers. Name the file after the platform type or domain check and keep each helper focused on one behavior.List or array types, when the conversion only reads one element. Prefer TargetBarcodeFormat.toMLKitFormat() plus formats.map { it.toMLKitFormat() } at the call site over Array<TargetBarcodeFormat>.toMLKitFormats().Int, String, Double, or Any, even privately. Prefer the domain type's companion/factory direction, such as BarcodeFormat.Companion.fromFormat(format: Int), over Int.toBarcodeFormat().Array<SomeDomainType> or List<SomeDomainType> and the body is mostly map { ... }, keep it in caller code.Int constants, apply the matching AndroidX/Java/Kotlin annotation where the API supports it, such as a CameraX @ImageCapture.FlashMode-style annotation on the function, return value, or parameter. Check the annotation target and retention before placing it; do not annotate blindly when the platform API exposes only a plain Int.Int, put the annotation on the format: Int parameter if the annotation target supports parameters. For example, prefer BarcodeFormat.Companion.fromFormat(@SomeBarcodeFormat format: Int) over an untyped primitive input.Hybrid*Spec class and include @Keep plus @DoNotStrip.Promise.async for suspending or I/O work and Promise.parallel for CPU-bound synchronous work.Promise<T> instances. Prefer Promise.async, Promise.parallel, Promise.resolved, and Promise.rejected; use a manual Promise only for real native completion/listener/callback bridges that cannot be wrapped as suspend APIs.Task<T>, first write a generic suspend adapter in its own extension file, such as Task+await.kt, then call it from Promise.async { task.await() }. Do not hand-wire addOnSuccessListener/addOnFailureListener/addOnCanceledListener into public HybridObject methods.Promise<Unit> for Promise<void>.NitroModules.applicationContext lazily and fail explicitly if it is unavailable.~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.