Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions docs/export/minerva.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,18 @@ build/minerva/TinySecureMlp/
host/
CMakeLists.txt
main.c
reference-input.txt
reference-output.txt
observed-output.txt # optional output from a real host run
firmware/
main.c
```

## Host Verification and CI

Host verification checks package structure, generated weight files, `model.npz` integrity, placeholder secret hygiene, and SKaiNET reference output generation. Add these metadata keys to opt into CMake, CTest, and parity comparison with a host output file:
Host verification checks package structure, generated weight files, `model.npz` integrity, placeholder secret hygiene, and SKaiNET reference fixture generation. The packager writes deterministic `host/reference-input.txt` and `host/reference-output.txt` files and records them in `manifest.json`. A real host run can write comma- or whitespace-separated float outputs to `host/observed-output.txt` for zero-config parity comparison.

Add these metadata keys to opt into CMake, CTest, and parity comparison with a custom host output file:

```kotlin
metadata = mapOf(
Expand All @@ -81,18 +86,22 @@ metadata = mapOf(
)
```

`HOST_OUTPUT_PATH` is optional when the host run writes `host/observed-output.txt`.

CI recipe:

```bash
./gradlew :skainet-compile:skainet-compile-minerva:jvmTest
./gradlew :skainet-compile:skainet-compile-minerva:minervaHostVerification \
-Pminerva.hostVerification.enabled=true \
-Pminerva.runtimeRoot="$MINERVA_RUNTIME_ROOT" \
-Pminerva.compilerScript="$MINERVA_COMPILER_SCRIPT"
cmake -S build/minerva/TinySecureMlp/host -B build/minerva/TinySecureMlp/host/build
ctest --test-dir build/minerva/TinySecureMlp/host/build --output-on-failure
-Pminerva.compilerScript="$MINERVA_COMPILER_SCRIPT" \
-Pminerva.calibrationNpz="$MINERVA_CALIBRATION_NPZ" \
-Pminerva.keyFile="$MINERVA_KEY_FILE"
```

`minervaHostVerification` is skipped by default. When enabled, it runs `jvmTest` and `runMinervaTinyMlpSample` with CMake and CTest host verification enabled unless `-Pminerva.hostVerification.runCmakeBuild=false` or `-Pminerva.hostVerification.runCTest=false` is set.

## ONNX to Minerva

Use the existing ONNX loader to inspect a model and reject unsupported operators before constructing a compatible SKaiNET `ComputeGraph`:
Expand Down
27 changes: 21 additions & 6 deletions docs/modules/ROOT/pages/how-to/minerva-export.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -128,15 +128,18 @@ build/minerva/TinySecureMlp/
host/
CMakeLists.txt
main.c
reference-input.txt
reference-output.txt
observed-output.txt # optional output from a real host run
firmware/
main.c
----

The manifest records the target, quantization, libminerva root, compiler command summary, NPZ schema version, layer count, and generated files. `secrets.example.h` contains placeholder values only.
The manifest records the target, quantization, libminerva root, compiler command summary, NPZ schema version, layer count, reference fixture paths, and generated files. `secrets.example.h` contains placeholder values only.

== Host Verification

Host verification always checks the package structure, generated weight files, `model.npz` integrity, and placeholder secret hygiene. It also computes the SKaiNET reference output for a deterministic reference input.
Host verification always checks the package structure, generated weight files, `model.npz` integrity, and placeholder secret hygiene. It also writes and validates deterministic `host/reference-input.txt` and `host/reference-output.txt` fixtures.

Use these metadata keys to opt into external host checks:

Expand All @@ -151,6 +154,8 @@ metadata = mapOf(

`RUN_CMAKE_BUILD` configures and builds `host/CMakeLists.txt`. `RUN_CTEST` runs the packaged CTest smoke test. `HOST_OUTPUT_PATH` lets a real host run write comma- or whitespace-separated float outputs that are compared with the SKaiNET reference output using `hostVerificationTolerance`.

`HOST_OUTPUT_PATH` is optional when the host run writes the default `host/observed-output.txt` file.

Local CI recipe:

[source,bash]
Expand All @@ -159,12 +164,12 @@ Local CI recipe:
./gradlew :skainet-compile:skainet-compile-minerva:minervaHostVerification \
-Pminerva.hostVerification.enabled=true \
-Pminerva.runtimeRoot="$MINERVA_RUNTIME_ROOT" \
-Pminerva.compilerScript="$MINERVA_COMPILER_SCRIPT"
cmake -S build/minerva/TinySecureMlp/host -B build/minerva/TinySecureMlp/host/build
ctest --test-dir build/minerva/TinySecureMlp/host/build --output-on-failure
-Pminerva.compilerScript="$MINERVA_COMPILER_SCRIPT" \
-Pminerva.calibrationNpz="$MINERVA_CALIBRATION_NPZ" \
-Pminerva.keyFile="$MINERVA_KEY_FILE"
----

The Gradle `minervaHostVerification` task is gated. It only runs when the `minerva.hostVerification.enabled`, `minerva.runtimeRoot`, and `minerva.compilerScript` properties are present.
The Gradle `minervaHostVerification` task is gated. It only runs when `minerva.hostVerification.enabled=true`, `minerva.runtimeRoot`, and `minerva.compilerScript` are present. When enabled, it runs `jvmTest` and `runMinervaTinyMlpSample` with `MINERVA_RUN_CMAKE=true` and `MINERVA_RUN_CTEST=true` by default. Override `-Pminerva.hostVerification.runCmakeBuild=false` or `-Pminerva.hostVerification.runCTest=false` only for runtime bring-up.

== Firmware Integration

Expand Down Expand Up @@ -227,6 +232,16 @@ Without `MINERVA_COMPILER_SCRIPT`, the sample task runs a dry validation through
-Pminerva.hostVerification.runCTest=true
----

For CI, prefer the gated verification profile:

[source,bash]
----
./gradlew :skainet-compile:skainet-compile-minerva:minervaHostVerification \
-Pminerva.hostVerification.enabled=true \
-Pminerva.compilerScript="$MINERVA_COMPILER_SCRIPT" \
-Pminerva.runtimeRoot="$MINERVA_RUNTIME_ROOT"
----

The sample graph is covered by `MinervaTinyMlpExportSampleTest`, which validates compatibility, lowering, and NPZ generation without requiring real device keys.

== Troubleshooting
Expand Down
20 changes: 16 additions & 4 deletions skainet-compile/skainet-compile-minerva/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,31 @@ val minervaCalibrationNpz = providers.gradleProperty("minerva.calibrationNpz")
val minervaRunCmakeBuild = providers.gradleProperty("minerva.hostVerification.runCmakeBuild")
val minervaRunCTest = providers.gradleProperty("minerva.hostVerification.runCTest")
val minervaHostOutputPath = providers.gradleProperty("minerva.hostVerification.hostOutputPath")
val minervaRunCmakeBuildForSample = minervaRunCmakeBuild
.orElse(providers.environmentVariable("MINERVA_RUN_CMAKE"))
.orElse(minervaHostVerificationEnabled.map { it.toString() })
val minervaRunCTestForSample = minervaRunCTest
.orElse(providers.environmentVariable("MINERVA_RUN_CTEST"))
.orElse(minervaHostVerificationEnabled.map { it.toString() })

val jvmMainCompilation = kotlin.targets.getByName("jvm").compilations.getByName("main")

tasks.register("minervaHostVerification") {
group = "verification"
description = "Gated lifecycle hook for external Minerva host verification in CI."
description = "Runs external Minerva compiler and host verification when explicitly configured."
enabled = minervaHostVerificationEnabled.get() &&
minervaRuntimeRoot.isPresent &&
minervaCompilerScript.isPresent
if (enabled) {
dependsOn("jvmTest")
dependsOn("jvmTest", "runMinervaTinyMlpSample")
}
inputs.property("minerva.runtimeRoot", minervaRuntimeRoot.orElse(""))
inputs.property("minerva.compilerScript", minervaCompilerScript.orElse(""))
inputs.property("minerva.calibrationNpz", minervaCalibrationNpz.orElse(""))
inputs.property("minerva.keyFile", minervaKeyFile.orElse(""))
inputs.property("minerva.hostVerification.runCmakeBuild", minervaRunCmakeBuildForSample)
inputs.property("minerva.hostVerification.runCTest", minervaRunCTestForSample)
inputs.property("minerva.hostVerification.hostOutputPath", minervaHostOutputPath.orElse(""))
}

tasks.register<JavaExec>("runMinervaTinyMlpSample") {
Expand All @@ -62,6 +73,7 @@ tasks.register<JavaExec>("runMinervaTinyMlpSample") {
dependsOn(tasks.named("jvmJar"))

mainClass.set("sk.ainet.compile.minerva.examples.MinervaTinyMlpExportSample")
workingDir = rootProject.projectDir

classpath = files(
jvmMainCompilation.runtimeDependencyFiles,
Expand All @@ -80,10 +92,10 @@ tasks.register<JavaExec>("runMinervaTinyMlpSample") {
minervaCalibrationNpz.orElse(providers.environmentVariable("MINERVA_CALIBRATION_NPZ")).orNull?.let {
environment("MINERVA_CALIBRATION_NPZ", it)
}
minervaRunCmakeBuild.orElse(providers.environmentVariable("MINERVA_RUN_CMAKE")).orNull?.let {
minervaRunCmakeBuildForSample.orNull?.let {
environment("MINERVA_RUN_CMAKE", it)
}
minervaRunCTest.orElse(providers.environmentVariable("MINERVA_RUN_CTEST")).orNull?.let {
minervaRunCTestForSample.orNull?.let {
environment("MINERVA_RUN_CTEST", it)
}
minervaHostOutputPath.orElse(providers.environmentVariable("MINERVA_HOST_OUTPUT_PATH")).orNull?.let {
Expand Down
Loading
Loading