Idea

Catch code that ignores its inputs

A function can have the right signature, compile, and return a plausible value while never using its inputs, and a test that only tries the usual case will still pass. Here we check whether declared inputs reach a function's result. This does not detect AI authorship: a person, a generator, or an intentional constant-returning implementation can write the same disconnected structure. The two functions below are real Bosatsu code (Bosatsu is a small, pure, total functional language; Yichus, the site you are reading, is a static-analysis toolkit for it) with the same signature. They ship in this repository at demos/detection/orders.bosatsu, and both compile. One reads the stored total and uses its input. The other returns a literal without using either source.

Code & run Run the two order functions
Path A
# Reads the stored total, adds this order's qty
def get_total_real(o: Order) -> IO[Int]:
  (
    c <- orders_cell.flat_map()
    stored <- c.read().flat_map()
    pure(add(stored, order_qty(o)))
  )
Path B
# Same signature. Never reads state,
# ignores the order, hard-codes the answer.
def get_total_fake(o: Order) -> IO[Int]:
  _ = o
  pure(123)
Both compile, and that is checked: the file ships in the repo and the analyzer runs on it. Each returns an IO[Int] that yields a number. Structurally, Path B never touches the state cell, and the order o is thrown away. (Reading Path A: x <- e.flat_map() is Bosatsu do-notation, meaning "run e, bind its result to x". The continuation lambda is supplied by the notation, so flat_map() takes no written argument. This is real Bosatsu syntax you can compile.) Takeaway: equal types do not imply equal input connectivity. Run the static analyzer on the linked source in the command-line section.

Inspect the current program’s structure

The editable example above compiles real Bosatsu. To inspect dependencies, parameter influence, IO sites and literal-result facts, open the Explorer workbench. Analyze the source, choose a binding, then use Overview or Trace Flow to follow the evidence back to the program.

Earlier versions of this page animated prepared signal cards. Those illustrations have been retired. Use the current compiler-derived facts to judge whether a function’s input connectivity matches its intended job.

Matchless Dependency and Influence Analysis

Yichus is built on Bosatsu, a total functional language. Explorer compiles typed Bosatsu to Matchless IR and uses compiler metadata to locate expressions.

The Explorer walks typed Global, local, IO, control, and literal structure to build dependency and influence facts. It can report that a parameter reaches return data, only affects a guard, or is unused. It can also report literal-only result ancestry. These are structural facts, not a correctness or authorship verdict.

Takeaway: use the report to locate an input-connectivity break, then review whether that break violates the program's intent. The implementation routes are ProgramFactsAnalyzer and DataflowAnalyzer.

Scope: the analyzer reads Bosatsu's compiled form only. It does not parse Python, TypeScript, or Java. The graph comes from the analyzer’s supported IR and compiler metadata. Purity and checked recursion help make analysis tractable, but do not make an analyzer complete or infallible. The research question is how useful these tools can become; it is described on the front page.

The signals are not a verdict. A function that legitimately returns constants, say a default config or a lookup table, produces the same literal-ancestry profile, and that is correct behavior. The signals state what is (no input reaches this output). Whether that is a bug is the reviewer's call. The fact tools are a CLI that pairs these structural facts with observations recorded from seeded runs, and they sharpen the call with run evidence. When a function ignores a parameter that should matter, the tools emit a fact reading varying parameter… the result never changed, and the reviewer weighs that.

Run the Input-Connectivity Check

Use the browser Explorer to compile and inspect an editable example, or run the command-line analyzer on the file below from a clone of the repo (github.com/snoble/yichus). You need a JVM 17+ and sbt. sbt assembly builds the analyzer jar, so yichus below means java -jar target/scala-*/yichus.jar:

yichus explore --agenda demos/detection/orders.bosatsu

Copy-pasteable route from a fresh clone on a Java 17 machine:

git clone https://github.com/snoble/yichus.git
cd yichus
JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 sbt --no-server assembly
JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 java -jar target/scala-*/yichus.jar explore --agenda demos/detection/orders.bosatsu

An agenda is the analyzer's worklist output: a list of cards, each stating one closed-form observation about the program. On this file it reports, among other cards (actual output): unused-parameter get_total_fake(o): “the parameter influences nothing in the binding (neither data nor guards)”. The full fact vocabulary, including literal-result and the run-evidence facts, is on the fact tooling page.

Property Digest and CI Baseline

The agenda reports one binding at a time. The property digest reports every binding at once, in a fixed shape you can diff. Use it to read what a package does without reading its source, and to catch a change that shifts a property.

The digest classifies each parameter by influence: return-data means the parameter's value reaches the result; guard-only means it steers control flow but its value never reaches the result; unused means it reaches neither. The analysis traces data flow through loop and recur accumulators and mutable slots, so the classification is sound over the recursive functional style these checkers use — a parameter marked unused has no modeled data or control influence. This is not a statement that its name never occurs in the source.

Run yichus properties over a package set. It prints one entry per binding: arity, IO effect kinds, per-struct field reads, package reach, and the per-parameter influence.

yichus properties protocol.bosatsu checker.bosatsu solution.bosatsu -o digest.json

For example, the client step handler in the secrecy task (eval/corpus/property-baseline/task-009-solution.json) reads only its state parameter; its two message parameters are marked unused:

{
  "package": "Bench/Dist009/Client",
  "name": "cli_step",
  "arity": 3,
  "params": [
    { "name": "_a", "influence": "unused" },
    { "name": "_b", "influence": "unused" },
    { "name": "s",  "influence": "return-data" }
  ]
}

You read that entry to check intent. A proof handler whose challenge parameter is unused does not really check the challenge. Here the unused parameters are the sender and the message, which this client ignores by design, so the entry is correct.

A committed baseline of this digest for the distributed-systems standard library and the security checkers lives under eval/corpus/property-baseline/. The test PropertyBaselineGoldenTest compares a fresh digest against the baseline on every run. A change that shifts a property — a parameter that was return-data becoming unused, a lost field read — fails the test with a per-binding delta. A reviewer reads the delta, not the whole file. When you intend the change, regenerate the baseline:

YICHUS_REGEN_GOLDEN=1 sbt "testOnly dev.yichus.analysis.PropertyBaselineGoldenTest"

Takeaway: the digest makes parameter-influence changes reviewable as data. Read the committed baseline artifacts and golden test for the exact gate.

Where this fits