cd /news/developer-tools/reading-static-verification-evidence… · home › topics › developer-tools › article
[ARTICLE · art-154850] src=dev.to ↗ pub= topic=developer-tools verified=true sentiment=· neutral

Reading static verification evidence: three exit codes, three review decisions

Kevin Kissi, founder and CEO of Zof, published a demonstration of Zof CLI 0.1.2 showing that its static verification command returns distinct exit codes for different outcomes: 0 for a clean addition function, 1 for a file containing eval, and 2 for a missing file. Kissi argues that a passing static check only proves the invocation completed without reporting a finding, not that tests ran or that a change is safe, and that reviewers should treat each exit code as a different decision signal. The examples are synthetic and were reproduced on macOS with Node 24.19.0 and Python 3.12.14 from a fresh npm install.

by read5 min views3 publishedOct 21, 2026

A passing command is useful evidence only when its meaning is clear. A static checker can complete successfully without running a test, observing production behavior, or proving that a software change is safe. Treating those outcomes as equivalent makes a release decision depend on work that never happened.

Three tiny TypeScript examples make the distinction concrete: a simple addition function, a function containing eval, and a requested file that does not exist. Captured runs of Zof CLI 0.1.2 returned exit codes 0, 1, and 2 respectively. Each outcome calls for a different response from a reviewer.

Disclosure: This article was drafted with AI assistance using captured command output and public documentation. Its examples are synthetic; they do not describe a customer incident or personal production experience.

Affiliation: Kevin Kissi is the founder and CEO of Zof.

The original demonstration ran on macOS with Node 24.19.0 and Python 3.12.14, using an existing CLI installation whose compiled distribution files matched the public package. A separate fresh install of 0.1.2 from the official npm registry then reproduced the commands below in a disposable project. All three exits matched; the JSON evidence matched except for generated identifiers and timestamps. These runs establish the examples’ behavior on that environment, not universal compatibility.

Use Node 22 or 24 and Python 3.10 or newer on Linux or macOS. The published instructions document these prerequisites. Installation is a separate step that downloads dependencies; --ignore-scripts disables package lifecycle scripts, while subsequent --no-install invocations decline installing a missing CLI. See the public CLI documentation.

mkdir zof-static-demo
cd zof-static-demo
node --version
python3 --version
npm init -y
npm install --ignore-scripts --no-audit --no-fund --save-exact @zof-ai/cli@0.1.2
npx --no-install zof --help

mkdir -p fixtures/clean fixtures/unsafe
cat > fixtures/clean/math.ts <<'TS'
export function add(a: number, b: number): number {
  return a + b
}
TS

cat > fixtures/unsafe/math.ts <<'TS'
export function evaluate(input: string): unknown {
  return eval(input)
}
TS

The second file is input to static analysis. Do not run its function. These verification commands inspect source; they do not execute the application or its tests.

Capture stdout, stderr, and the process exit code separately. The conditional preserves expected nonzero results even in a shell configured to stop on errors:

run_case() {
  case_name=$1
  case_root=$2
  case_file=$3
  if npx --no-install zof verify --root "$case_root" \
      --changed "$case_file" --json \
      >"$case_name.stdout.json" 2>"$case_name.stderr.txt"; then
    case_exit=0
  else
    case_exit=$?
  fi
  printf '%s exit=%s\n' "$case_name" "$case_exit"
}

run_case clean fixtures/clean math.ts
run_case unsafe fixtures/unsafe math.ts
run_case missing-file fixtures/clean missing.ts

The captured exits were:

clean exit=0
unsafe exit=1
missing-file exit=2

For the addition function, the evidence reports execution.status: completed and execution.result: pass. Findings, tests, and artifacts are empty arrays. The tool identifies itself as zof-cli version 0.1.2, with evidence type static-analysis.

That supports a narrow conclusion: this invocation completed without reporting a finding. It supplies no test result. An empty tests array cannot establish that arithmetic edge cases, integration behavior, or deployment configuration were checked.

The impact object also reports confidence: high and complete: true. Those fields must be read alongside its limitations. Because the invocation supplies an explicit file list, EXPLICIT_FILES says line changes and changed symbols are unavailable. The source repository and commit are both null in this synthetic example. Neither a reassuring confidence label nor an empty findings list fills those gaps.

For the eval example, execution completes with result fail. The captured finding identifies the review location precisely:

{
  "id": "dynamic-evaluation",
  "severity": "high",
  "message": "Dynamic code evaluation requires review; do not evaluate untrusted input.",
  "path": "math.ts",
  "line": 2
}

The impact result changes too: confidence is low, completeness is false, and DYNAMIC_EXECUTION records an analysis limitation. This matters beyond the exit code. The checker has identified a construct it cannot fully analyze, so a reviewer should investigate the input's origin and whether dynamic evaluation is necessary.

The finding does not demonstrate an exploit or establish that every input is hostile. It provides a specific reason to inspect the code. Replacing dynamic evaluation with explicit operations may be appropriate, but that decision depends on the intended behavior. Any resulting tests should be recorded as separate evidence; none ran here.

Requesting missing.ts produces exit 2. Stdout is empty, even though the command requested JSON. Stderr contains:

ZOF_INPUT_ERROR: check command, workspace, bounded relative paths and configuration; use zof help. No input details were logged.

A consumer that treats empty output as an empty findings list would turn an input error into false reassurance. Check the exit code before parsing evidence. The documented meanings distinguish successful completion, a configured failure, and invalid or incomplete execution. In this example, the last category requires fixing the requested path and rerunning the check.

Environment failures deserve the same attention. An earlier preserved attempt selected an unsuitable Python runtime and failed closed. Correcting the runtime path enabled the recorded runs. Reproducibility includes prerequisites and unsuccessful execution, not just the final green result.

For a real change, retain the command, tool version, inspected files, both output streams, and process exit. Check whether repository and commit attribution are present. Read findings and limitations before interpreting confidence or completeness. Then identify the additional evidence the change requires, such as behavior tests or integration checks.

The three cases establish a useful boundary: the clean example completed its static check; the dynamic example produced a concrete review finding; the missing-file example produced no successful verification result. A human release review can use those facts without silently expanding their scope. The decision should explain what was checked, what remains uncertain, and which additional checks support shipping the change.

── more in #developer-tools 4 stories · sorted by recency
── more on @zof 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host ✓
Get free account → Pricing
from €0/mo · no card required
LIVE [news/reading-static-verif…] indexed:0 read:5min 2026-10-21 · —