skainet-java-interop — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited skainet-java-interop (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.
Rules for making SKaiNET features usable from Java without surfacing Kotlin-specific machinery. Java is the first guest language after Kotlin, so its ergonomics are a constraint — not an afterthought.
skainet-*/src/jvmMain/kotlin/sk/ainet/java/.skainet-test-java module to prove the Java surface.kotlin.skainet-testing (the Java JUnit pattern is documented there).kmp.skainet-test-java — gradle-multimodule.@file:JvmName("...") followed by package sk.ainet.java. The JvmName matches what Java users will type as the class identifier (SKaiNET, TensorJavaOps, <Feature>JavaOps).public object Name { ... }. Never expose top-level public fun foo(...) to Java callers — Java sees them as static methods on a synthetic <FileName>Kt class.SKaiNET.INSTANCE.context() instead of SKaiNET.context(). This rule applies to every public function and every property accessor on the Java-facing object.@JvmOverloads synthesises overloads with progressively fewer parameters from right to left. Apply it to every @JvmStatic function that has a default value.value class types (Java sees the boxed form, defeats the purpose)inline fun (the bytecode shape is unfriendly)Result<T> (no Kotlin runtime in pure Java contexts; consumers can't unwrap)X.() -> Y) — Java users cannot supply themSequence<T> (no Java-native iteration); use Iterable<T> or a primitive array insteadTensor<*, *> for any tensor crossing the boundary and cast internally with @Suppress("UNCHECKED_CAST"). See TensorJavaOps.add` for the canonical pattern.FloatArray, IntArray, DoubleArray, ByteArray — Java sees them as primitive arrays (float[], int[], …), zero boxing.KClass<T>; expose DType instances (DType.fp32(), DType.int32()) and resolve to KClass internally.@JvmStatic member ⇒ new @Test in skainet-test-java.skainet-*/src/jvmMain/kotlin/sk/ainet/java/. Mirror its @file:JvmName, package declaration, KDoc-with-Java-example header, and member shape.object (or extend an existing one).@JvmStatic is mandatory; @JvmOverloads if any parameter has a default; primitive arrays for bulk data; Tensor<*, *> for tensors crossing the boundary.Tensor<DType, Any?>) and delegating to the Kotlin API.skainet-test-java/src/test/java/sk/ainet/java/<Feature>JavaOpsTest.java proving the surface compiles and runs from Java.Before declaring the change complete:
@file:JvmName("...") (line 1).package sk.ainet.java.public object.@JvmStatic.@JvmOverloads.value class, no Result<T>, no Sequence<T>, no receiver-typed lambdas in any signature.Tensor<*, *>.DType instance, not KClass<DType>.skainet-test-java/.../<Feature>JavaOpsTest.java exercising at least one method of the new surface.Entry-point factory:
@file:JvmName("SKaiNET")
package sk.ainet.java
import sk.ainet.context.DirectCpuExecutionContext
import sk.ainet.context.ExecutionContext
import sk.ainet.lang.tensor.Shape
import sk.ainet.lang.tensor.Tensor
import sk.ainet.lang.types.DType
import sk.ainet.lang.types.FP32
import kotlin.reflect.KClass
public object SKaiNET {
@JvmStatic
public fun context(): ExecutionContext =
DirectCpuExecutionContext.create()
@JvmStatic
public fun tensor(ctx: ExecutionContext, shape: IntArray, dtype: DType, data: FloatArray): Tensor<*, *> {
@Suppress("UNCHECKED_CAST")
val kclass = dtype::class as KClass<DType>
return ctx.fromFloatArray<DType, Any?>(Shape(*shape), kclass, data)
}
@JvmStatic
@JvmOverloads
public fun zeros(ctx: ExecutionContext, shape: IntArray, dtype: DType = FP32): Tensor<*, *> {
@Suppress("UNCHECKED_CAST")
val kclass = dtype::class as KClass<DType>
return ctx.zeros<DType, Any?>(Shape(*shape), kclass)
}
}
// from: SKaiNET/skainet-backends/skainet-backend-cpu/src/jvmMain/kotlin/sk/ainet/java/SKaiNET.kt:1-102Ops facade — every member `@JvmStatic`, defaults via `@JvmOverloads`:
@file:JvmName("TensorJavaOps")
package sk.ainet.java
public object TensorJavaOps {
@JvmStatic
public fun add(a: Tensor<*, *>, b: Tensor<*, *>): Tensor<*, *> {
@Suppress("UNCHECKED_CAST")
val ta = a as Tensor<DType, Any?>
@Suppress("UNCHECKED_CAST")
val tb = b as Tensor<DType, Any?>
return ta.ops.add(ta, tb)
}
@JvmStatic
public fun matmul(a: Tensor<*, *>, b: Tensor<*, *>): Tensor<*, *> { /* ... */ }
@JvmStatic
@JvmOverloads
public fun softmax(a: Tensor<*, *>, dim: Int = -1): Tensor<*, *> { /* ... */ }
}
// from: SKaiNET/skainet-lang/skainet-lang-core/src/jvmMain/kotlin/sk/ainet/java/TensorJavaOps.kt:1-322Mirror Java JUnit test that proves the surface from a Java caller:
package sk.ainet.java;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import sk.ainet.context.ExecutionContext;
import sk.ainet.lang.tensor.Tensor;
import sk.ainet.lang.types.DType;
import static org.junit.jupiter.api.Assertions.*;
class TensorJavaOpsTest {
private static ExecutionContext ctx;
@BeforeAll
static void setUp() { ctx = SKaiNET.context(); }
@Test
void add() {
Tensor<?, ?> a = SKaiNET.tensor(ctx, new int[]{2, 2}, DType.fp32(),
new float[]{1f, 2f, 3f, 4f});
Tensor<?, ?> b = SKaiNET.tensor(ctx, new int[]{2, 2}, DType.fp32(),
new float[]{10f, 20f, 30f, 40f});
Tensor<?, ?> c = TensorJavaOps.add(a, b);
assertArrayEquals(new int[]{2, 2}, c.getShape().getDimensions());
float[] result = c.getData().copyToFloatArray();
assertArrayEquals(new float[]{11f, 22f, 33f, 44f}, result, 1e-6f);
}
}
// from: SKaiNET/skainet-test/skainet-test-java/src/test/java/sk/ainet/java/TensorJavaOpsTest.java:1-38../kotlin/SKILL.md.jvmMain for facades) — see ../kmp/SKILL.md.skainet-test-java and adding the Java test — see ../gradle-multimodule/SKILL.md and ../skainet-testing/SKILL.md.skainet-data-dsl skill (in the sibling consumer plugin).skainet-java-consumer skill (in the sibling consumer plugin).// WRONG — top-level fun; Java sees it as TensorOpsKt.add
@file:JvmName("TensorOps")
package sk.ainet.java
public fun add(a: Tensor<*, *>, b: Tensor<*, *>): Tensor<*, *> = ...// RIGHT — public object + @JvmStatic
@file:JvmName("TensorJavaOps")
package sk.ainet.java
public object TensorJavaOps {
@JvmStatic
public fun add(a: Tensor<*, *>, b: Tensor<*, *>): Tensor<*, *> = ...
}// WRONG — defaults without @JvmOverloads; Java cannot omit `dim`
@JvmStatic
public fun softmax(a: Tensor<*, *>, dim: Int = -1): Tensor<*, *> = ...// RIGHT — @JvmOverloads
@JvmStatic
@JvmOverloads
public fun softmax(a: Tensor<*, *>, dim: Int = -1): Tensor<*, *> = ...// WRONG — exposing KClass to Java
@JvmStatic
public fun tensor(ctx: ExecutionContext, shape: IntArray, dtype: KClass<DType>, data: FloatArray): Tensor<*, *> = ...// RIGHT — DType instance
@JvmStatic
public fun tensor(ctx: ExecutionContext, shape: IntArray, dtype: DType, data: FloatArray): Tensor<*, *> = ...// WRONG — Sequence + receiver lambda
@JvmStatic
public fun forEachLayer(model: Module<*, *>, action: Module<*, *>.(Layer) -> Unit)// RIGHT — plain Iterable + java.util.function.BiConsumer (or specialised interface)
@JvmStatic
public fun forEachLayer(model: Module<*, *>, action: java.util.function.BiConsumer<Module<*, *>, Layer>)references/jvm-annotations.md — every @Jvm* annotation we use, when to apply each.references/forbidden-signatures.md — exhaustive list of Kotlin shapes that MUST NOT cross the Java boundary, with rewrites.~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.