skillZs
★ LIVE SKILL TAGS ★
>>> LIVE SKILLS INDEX <<<
* OPEN SOURCE *
NO LOGIN, NO TRACKING
※ REAL INSTALL DATA ※
← back to all skills
kali-decoder/midnight-skills122 installs

testing

Debug Compact contracts and manage toolchain versions. Covers static vs dynamic errors, reading compiler messages, the --skip-zk dev loop, version synchronization, and common traps.

How do I install this agent skill?

npx skills add https://github.com/kali-decoder/midnight-skills --skill testing
view source ↗

Is this agent skill safe to install?

  • Gen Agent Trust Hubpass

    This skill provides educational content and troubleshooting guidance for developers working with Compact contracts on the Midnight network. No security risks were identified.

  • Socketpass

    No alerts

  • Snykpass

    Risk: LOW · No issues

What does this agent skill do?

Scope This skill covers the two error layers in Compact (static vs dynamic), how to read compiler messages (especially undeclared disclosure traces), the fast development loop with --skip-zk, version management across 6 components, and the most common debugging patterns. Official testing docs are "coming soon" — this is battle-tested from real development.

1) Two Error Layers

Compact has two error types, not one:

Static errors — Caught by the compiler before generating any output. You see these in your terminal while developing. Static errors are your friend — the compiler tells you exactly what's wrong and where.

Dynamic errors — Caught at runtime by the generated JavaScript. You see these when a circuit executes. These are harder to debug because they happen inside generated code you didn't write.

Static Errors (Compile Time)

Error typeWhat it isWhen caught
SyntaxMalformed codeParser
Type mismatchWrong type usedType checker
Undeclared disclosuredisclose() missingWitness protection
Undefined referenceUnknown identifierName resolver
Generic not specializedGeneric entity used at top levelScope checker
Recursive structStruct refers to itselfDeclaration checker
Recursive circuitCircuit calls itselfDeclaration checker
return in forreturn inside loopStatement checker
Sealed ledger writeWrite to sealed field in circuitDeclaration checker

If the compiler produces no output, there's at least one static error. Check the messages.

Dynamic Errors (Runtime)

Error typeWhat it isExample
Type mismatchWrong argument type/numberCalling with wrong args
OverflowCast value too large for target1000 as Uint<8>
UnderflowCounter decremented below zerocounter -= 1 when at 0
Uninitialized nested valueNested ledger state not initializedmap.lookup(k).lookup(k2) before insert
Merkle tree fullInsert into full treetree.insert() when isFull()

Dynamic errors are harder to debug. Read the error message for the line number in your source file.

2) Reading Compiler Error Messages

Type Error

/path/contract.compact line 12 char 5:
  type error: expected Uint<64>, got Field

Read: line:character, expected type, got type. The caret (^) points to the problem token.

Undeclared Disclosure

Exception: /path/contract.compact line 6 char 11:
  potential witness-value disclosure must be declared but is not:
    witness value potentially disclosed:
      the return value of witness getBalance at line 2 char 1
    nature of the disclosure:
      ledger operation might disclose the witness value
    via this path through the program:
      the right-hand side of = at line 6 char 11

Read this bottom to top. The path traces how witness data traveled:

  1. Origin: getBalance() at line 2
  2. Path: flows through the right-hand side of the assignment
  3. Destination: the ledger operation at line 6

Fix: Add disclose() somewhere along that path, as close to the disclosure point as possible.

Missing disclose() on Return

Exception: line 5 char 3:
  potential witness-value disclosure must be declared but is not:
    witness value potentially disclosed:
      the return value of witness getBalance at line 2 char 1
    nature of the disclosure:
      the value returned from exported circuit check might disclose
      the result of a comparison involving the witness value

Even a Boolean comparison result counts as disclosure. Wrap the witness call or the return value with disclose().

Version Mismatch

Error: runtime version mismatch: expected 0.15.0, got 0.14.2

The compiled contract expects a different runtime version. See version management below.

3) The --skip-zk Development Loop

Generating proving keys is slow. During iterative development, skip it:

compact compile --skip-zk contracts/contract.compact contracts/managed/contract

This produces contract/index.js and compiler/contract-info.json, enough to test logic. Re-enable for final builds.

4) Version Management

Midnight has 6 components that must stay in sync. When they're not, you get opaque runtime errors about version mismatches.

ComponentWhat it isHow to check
CLI toolcompact binarycompact --version
Compilercompactccompact compile --version
Runtime@midnight-ntwrk/compact-runtimenpm list
Ledger@midnight-ntwrk/ledger-v8npm list
JS libraries@midnight-ntwrk/midnight-js-*npm list
Proof serverDocker imageimage tag

Check Current Versions

compact --version
compact compile --version
npm list @midnight-ntwrk/compact-runtime
npm list @midnight-ntwrk/ledger-v8

Consult the Compatibility Matrix

The official release compatibility matrix is the source of truth. Never mix versions without checking it.

Lock Exact Versions in package.json

{
  "dependencies": {
    "@midnight-ntwrk/compact-runtime": "0.15.0",
    "@midnight-ntwrk/ledger-v8": "8.0.3"
  }
}

Do not use ^ or ~ — these allow automatic updates that silently break compatibility.

Use npm ci for Reproducible Installs

rm -rf node_modules
npm ci

npm ci installs exactly what's in package-lock.json. npm install fetches the latest matching version.

After Updating Any Component

  1. Update all related components together
  2. Recompile contracts
  3. Restart the proof server with the new Docker image
  4. Run your test suite

5) Common Mistakes and Fixes

Forgot disclose() on Ledger Write

// wrong — compiler error
balance = getBalance();

// correct
balance = disclose(getBalance());

Forgot disclose() on Return Value

// wrong — compiler error (comparison of witness data)
export circuit check(n: Uint<64>): Boolean {
  return getSecret() > n;
}

// correct — declare the disclosure
export circuit check(n: Uint<64>): Boolean {
  return disclose(getSecret()) > n;
}

return Inside for Loop

// wrong — static error
circuit findFirst(v: Vector<4, Field>, target: Field): Boolean {
  for (const x of v) {
    if (x == target) return true;
  }
  return false;
}

// correct — use fold
circuit findFirst(v: Vector<4, Field>, target: Field): Boolean {
  return fold((found, x) => found || x == target, false, v);
}

Recursive Circuit

// wrong — static error: recursion not allowed
circuit factorial(n: Uint<64>): Uint<64> {
  return n == 0 ? 1 : n * factorial(n - 1);
}

Rewrite using fold or explicit unrolling. Compact requires finite circuits.

Narrowing Cast Overflows at Runtime

const x: Uint<64> = 1000;
const y = x as Uint<8>;  // dynamic error: 1000 doesn't fit

Always verify the value fits before casting. Use assert or bounded types.

Uninitialized Nested Ledger State

ledger fld: Map<Boolean, Map<Field, Counter>>;

// wrong — dynamic error (inner map not initialized)
export circuit increment(b: Boolean, n: Field): [] {
  fld.lookup(b).lookup(n) += 1;
}

// correct — initialize first
export circuit init(b: Boolean): [] {
  fld.insert(disclose(b), default<Map<Field, Counter>>);
}

transientHash Result Used Without disclose()

// wrong — compiler error (witness-tainted)
ledger h: Field;
export circuit store(v: Field): [] {
  h = transientHash<Field>(v);
}

// correct — declare disclosure
h = disclose(transientHash<Field>(v));

// or use transientCommit (nonce provides hiding, no disclose needed)
h = transientCommit<Field>(v, nonce);

6) Common Environment Issues

ErrorCauseFix
compact: command not foundBinary not on PATHexport PATH="$HOME/.compact/bin:$PATH"
ERR_UNSUPPORTED_DIR_IMPORTNode.js tried to import directoryOpen new terminal, clear caches
Docker connection errorsDocker Desktop not runningStart Docker Desktop
Port 6300 in useAnother container on same port-p 6301:6300
Version mismatch at runtimeOutdated runtime packageCheck compatibility matrix, update

7) Version Check Script

Run this before filing a bug report:

#!/bin/bash
echo "=== Midnight Version Check ==="
echo "CLI:"; compact --version || echo "not found"
echo "Compiler:"; compact compile --version || echo "not found"
echo "Runtime:"
npm list --depth=0 | grep @midnight-ntwrk || echo "none found"
echo "Node.js:"; node --version
echo "Compare with: docs.midnight.network/relnotes/support-matrix"

8) Getting Help

If stuck after checking these notes:

  1. Discord #dev-chat — post your error message and version details
  2. FAQ — docs.midnight.network/troubleshoot/faq
  3. Forum — forum.midnight.network

Always include:

  • Output of the version check script
  • The full error message
  • The .compact file (or relevant excerpt)
  • What you expected vs what happened

9) Quick Recap

  • Static errors — compiler catches them before output. Check the messages.
  • Dynamic errors — happen at runtime inside generated code. Read the line numbers.
  • Undeclared disclosure trace — read bottom to top, it traces the path from origin to disclosure.
  • Use --skip-zk during development. Enable for final builds.
  • Lock exact versions in package.json. Use npm ci.
  • Check the compatibility matrix before updating any component.
  • After any update: recompile, restart proof server, run tests.

Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.

<a href="https://skillzs.dev/skills/kali-decoder/midnight-skills/testing">View testing on skillZs</a>