Skip to content

feat(ground-truth): wire real CI, read op params from GGUF metadata - #989

Merged
michalharakal merged 2 commits into
developfrom
feat/groundtruth-metadata-params
Aug 13, 2026
Merged

michalharakal merged 2 commits into
developfrom
feat/groundtruth-metadata-params

Conversation

@michalharakal

Copy link
Copy Markdown
Contributor

Summary

Ground-truth validation existed as working Kotlin code but was dormant in practice:

  • No CI workflow actually ran it — TESTING.md's .github/workflows/ground-truth.yml
    example block was never a real file.
  • Every test silently skips (Assume.assumeTrue) when the sibling
    ../skainet-ground-truth checkout or generated GGUF files aren't present — the
    default state of any fresh clone or CI runner. Green CI proved nothing.
  • Operation parameters were guessed from the human-readable description text
    (desc.contains("padded") -> padding(1)), even though the Python writer already
    serializes them as real op.* GGUF metadata that was simply never read.

Changes

Metadata-driven op params (the correctness fix):

  • GroundTruthLoader.extractOpParams/decodeFieldValue: parse every op.* GGUF field
    into GroundTruthTestCase.rawOpParams.
  • GroundTruthTestCase.resolvedParams(): maps that onto OperationParams' typed fields.
  • GroundTruthValidator's validate/assertValid (and the validateWith/
    assertValidWith extensions) now default params to testCase.resolvedParams()
    instead of an empty OperationParams(). The JVM convenience overloads take
    OperationParams? = null instead, so "not specified" falls through to the
    per-test-case default rather than silently overriding it.
  • Deleted GroundTruthIntegrationTest's inferConv2dParams/inferOperationParams
    string-matching entirely.

Verified against real Docker-generated data — and this immediately surfaced a real gap
in the ground-truth fixtures themselves (three TS-001 conv2d cases had
stride/padding baked into the PyTorch call but never recorded in op_params), fixed
in the companion skainet-ground-truth PR:
SKaiNET-developers/skainet-ground-truth#3.
With that fix, TS-001 goes from 3/6 to 6/6 passing.

CI: make dormancy visible, then fix it:

  • GroundTruthConfig.requireAvailable/TestAssumptions.kt: -PrequireGroundTruth=true
    turns missing ground truth into a hard check() failure instead of a skip. Verified
    both directions.
  • New .github/workflows/ground-truth.yml: checks out skainet-ground-truth as a
    sibling (matching what build.gradle.kts already expected), builds the Docker image,
    generates GGUF fixtures, runs jvmTest -PrequireGroundTruth=true.
  • Uses --no-configuration-cache throughout — CI's ci-gradle.properties enables the
    config cache by default, and the ground-truth Gradle tasks hit a pre-existing
    (reproduced identically on unmodified develop, not introduced here) "cannot
    serialize Gradle script object references" config-cache incompatibility.
  • build.gradle.kts: the fixture source directory is now overridable via
    -PgroundTruthSourceDir (defaults to today's sibling-checkout convenience) — the
    numcrux-readiness piece, so SKaiNET's consumer doesn't hardcode where the fixtures
    physically live.

Test plan

  • ./gradlew :skainet-test:skainet-test-groundtruth:compileKotlinJvm :skainet-test:skainet-test-groundtruth:compileTestKotlinJvm — clean compile
  • Rebuilt the ground-truth Docker image, regenerated all 7 real test suites, ran
    the actual validation tests against them
  • Confirmed -PrequireGroundTruth=true genuinely fails (not skips) with the
    results directory absent, and skips cleanly without the flag
  • Ran the exact command sequence the new workflow runs
    (--no-configuration-cache buildGroundTruthDocker generateGroundTruth jvmTest -PrequireGroundTruth=true) end-to-end — exits 0

Follow-ups (Python-side op coverage expansion, a decision on gradient validation which
is currently fully unimplemented despite the "gradienttracer" name, and the numcrux
transfer itself) are tracked in #984 and its sub-issues — out of scope here.

Ground-truth validation existed as working Kotlin code but was dormant in
practice: no CI workflow actually ran it (TESTING.md's example block was
never a real file), and every test silently skips when the sibling
../skainet-ground-truth checkout or generated GGUF files aren't present —
so a broken pipeline showed green, not red.

## Op parameters come from GGUF metadata now, not guessed English text

gt/pytorch/io/writer.py already writes op.padding/op.stride/op.groups/etc.
as real GGUF metadata (op_params passed to @eXecutable), but
GroundTruthLoader never read it — GroundTruthIntegrationTest instead
string-matched the human-readable description ("padded" -> padding(1),
"strided" -> stride(2)) to guess parameters, silently wrong for any case
whose description didn't happen to contain the right word.

- GroundTruthLoader.extractOpParams/decodeFieldValue: parse every op.*
  field into GroundTruthTestCase.rawOpParams (Int/Float/List, scalar or
  array).
- GroundTruthTestCase.resolvedParams(): maps rawOpParams onto
  OperationParams' named fields.
- GroundTruthValidator.validate/assertValid and the validateWith/
  assertValidWith extensions now default params to
  testCase.resolvedParams() instead of an empty OperationParams() -- the
  JVM-side convenience overloads (GroundTruthLoader.kt) take
  OperationParams? = null instead, so "not specified" can still fall
  through to the per-test-case default rather than silently overriding it.
- Deleted GroundTruthIntegrationTest's inferConv2dParams/
  inferOperationParams entirely.

Verified against real data: rebuilt the ground-truth Docker image,
regenerated all 7 test suites, and found the fix immediately surfaced a
real data gap it was designed to catch -- three TS-001 conv2d cases
(UC-001's second function, UC-002, UC-003) set stride=2/padding=1 on the
actual torch.nn.Conv2d call but never passed them via op_params, so
nothing recorded that parameter at all. Fixed in skainet-ground-truth
(separate commit there). TS-001 went from 3/6 to 6/6 passing; TS-003
(flatten, already had start_dim/end_dim recorded) was 5/5 before and
after, confirming the metadata path was already correct there.

## CI: make dormancy visible, then fix it

- GroundTruthConfig.requireAvailable / TestAssumptions.kt: with
  -PrequireGroundTruth=true, missing ground truth is check()-failure, not
  Assume.assumeTrue skip. Verified both directions by removing the local
  results dir: without the flag the suite still skips cleanly (dev
  convenience preserved); with it, all four ground-truth tests fail
  loudly instead.
- New .github/workflows/ground-truth.yml: checks out skainet-ground-truth
  as a sibling (path: ../skainet-ground-truth, matching what
  build.gradle.kts already expected), builds the Docker image, generates
  GGUF fixtures, runs jvmTest -PrequireGroundTruth=true. Uses
  --no-configuration-cache throughout -- CI's ci-gradle.properties
  enables the config cache by default, and buildGroundTruthDocker/
  generateGroundTruth/cleanGroundTruth/listGroundTruth all hit a
  pre-existing (not introduced here, reproduced on unmodified develop)
  "cannot serialize Gradle script object references" config-cache
  incompatibility that would otherwise fail every run.
- build.gradle.kts: groundTruthProjectDir is now overridable via
  -PgroundTruthSourceDir (defaults to today's sibling-checkout
  convenience) -- the numcrux-readiness piece: SKaiNET's consumer no
  longer hardcodes where the fixtures physically live.

Verified end-to-end: ./gradlew --no-configuration-cache
buildGroundTruthDocker generateGroundTruth
jvmTest -PrequireGroundTruth=true, the exact command sequence the new
workflow runs, exits 0 against real Docker-generated fixtures.

Follow-ups (Python-side coverage expansion, gradient validation decision,
numcrux transfer) tracked in #984 and its sub-issues -- not attempted
here, out of scope for "make the existing pipeline real."
actions/checkout's `path: ../skainet-ground-truth` failed hard on the
first real run: "Repository path '/home/runner/work/SKaiNET/
skainet-ground-truth' is not under '/home/runner/work/SKaiNET/SKaiNET'"
-- the action explicitly rejects any path resolving outside the
checkout's own workspace, so a true sibling checkout via `path: ..` was
never actually possible, not just untested.

Fixed by checking out to a plain subdirectory (path: skainet-ground-truth,
inside SKaiNET's own workspace) and pointing every Gradle invocation at
it explicitly via -PgroundTruthSourceDir=$GITHUB_WORKSPACE/
skainet-ground-truth/pytorch -- the override groundTruthProjectDir
already supports. Local dev is unaffected: the sibling-checkout default
stays in place for anyone who already has skainet-ground-truth cloned
next to SKaiNET.

Verified locally: -PgroundTruthSourceDir pointed at the same
skainet-ground-truth checkout used throughout this PR's earlier testing,
confirmed listGroundTruth finds the real generated fixtures through the
override.
@michalharakal
michalharakal requested a review from aharakal August 13, 2026 14:55
@michalharakal
michalharakal merged commit 8cbb624 into develop Aug 13, 2026
12 checks passed
@michalharakal
michalharakal deleted the feat/groundtruth-metadata-params branch August 13, 2026 15:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants