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
# 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))) )
# Same signature. Never reads state, # ignores the order, hard-codes the answer. def get_total_fake(o: Order) -> IO[Int]: _ = o pure(123)
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.