Skip to content

DataFlowBench v0.6.0

Choose a tag to compare

@DavidBakerEffendi DavidBakerEffendi released this 01 Sep 07:11
· 55 commits to main since this release
8b70fd3

DataFlowBench v0.6.0

Sixth immutable release snapshot, and three things at once: the release in
which the benchmark doubles its analyzer count from four to eight — adding
OpenTaint, Infer v1.3.0, FlowDroid 2.15.1, and Pysa — the first
pin-currency review (#92)
, in which three reference tools are bumped and
nothing moves, and the first publication of the latency-characterization
tier
. All eight analyzers are bound at one fixture revision under the
freeze/v1 contract with claim scope release.

Freeze identity

  • Freeze ID (manifest SHA-256):
    3228af686d09f8666989368483bef375bb28b94025b55e31eaa7a0bdd29506ee
  • Manifest: reports/freeze.json
  • Benchmark revision: 8b70fd3 (tag v0.6.0)
  • Fixture revision:
    sha256:9df209ed3d7723a3ee33f2b289cf2afe34a3add781bdf2a2ac445de42b8d0151
  • Case schema v2, normalized result schema v1
  • 852 frozen cases, 74 bound reports, 3336 scored case results
  • Score tiers: calibration, core, language-extension, modeling
  • Model profiles: benchmark-controlled, tool-native
  • Claim exclusions: none

The fixture revision is unchanged from v0.5.0. The benchmark did not grow
in this release; its analyzer coverage did.

The eight analyzers

Analyzer Version Status this cycle
Bifrost 0.10.7 Held. v0.10.8 is dated but unreleased — see the pin-currency review below
CodeQL 2.26.4 Bumped from 2.26.3
Joern 4.0.614 Bumped from 4.0.610
Semgrep CE 1.175.0 Bumped from 1.174.0
OpenTaint analyzer/2026.08.27.17eb0fe New (#96), Java and Kotlin, amended by A11
Infer v1.3.0 New (#97), C, C++, and Java
FlowDroid 2.15.1 New (#99), Java and Kotlin
Pysa 0.10.0 (pyre-check) with Pyrefly 1.2.0 New (#100), Python

Every row's build identity is witnessed from the binary actually invoked and
digest-recorded in the manifest, including on the runs that decide nothing.

The four new adapters enter whole expanded cores. None of them fences a
partition: their pinned distributions declare interprocedural taint analysis
and document nothing this benchmark exercises as out of scope, so every
incapacity they show below is a measured mismatch, not a declared decline.
That is a harsher setting than Semgrep CE's, whose bounded intraprocedural
partition is preregistered, and the two must not be read against each other on
a raw n/58.

Their language footprints also change what some kernels can be read as. Infer
joins Bifrost, CodeQL, and Semgrep CE on the c and cpp cores — the third
analyzer there to enter the whole core rather than a declared partition, and
the first that is neither this project's own engine nor CodeQL. Pysa makes
python a five-analyzer kernel. Java goes from four analyzers to seven.

Results

Generated pages live in results/ and derive exclusively from the frozen
manifest; see results/index.md. Incomplete outcomes (inconclusive,
unsupported, runner-error) are capability and execution coverage and are
never counted as clean negatives.

The kernels

Correct decisions (true positives plus true negatives) on each kernel's core
tier, with incomplete outcomes shown beside them. Each language is its own
population with its own denominator, and each analyzer column is read
independently: DataFlowBench publishes no combined leaderboard, and cores of
different sizes are never pooled. n/a means the analyzer has no report for
that kernel in this freeze — no extractor, no frontend, or no adapter — which
is coverage, not a score.

Kernel core Bifrost 0.10.7 CodeQL 2.26.4 Joern 4.0.614 Semgrep CE 1.175.0 OpenTaint Infer v1.3.0 FlowDroid 2.15.1 Pysa 0.10.0
Java (29 templates, 58 assertions) 37/58 (20 inc) 48/58 47/58 12/58 (44 uns) 49/58 50/58 49/58 n/a
JavaScript (29 templates, 58 assertions) 36/58 (22 inc) 48/58 44/58 12/58 (44 uns) n/a n/a n/a n/a
TypeScript (29 templates, 58 assertions) 34/58 (24 inc) 48/58 n/a 12/58 (44 uns) n/a n/a n/a n/a
Python (29 templates, 58 assertions) 36/58 (22 inc) 48/58 48/58 12/58 (44 uns) n/a n/a n/a 47/58
Kotlin (29 templates, 58 assertions) 28/58 (30 inc) 46/58 n/a 12/58 (44 uns) 50/58 n/a 49/58 n/a
Scala (29 templates, 58 assertions) 38/58 (20 inc) n/a n/a n/a n/a n/a n/a n/a
C# (29 templates, 58 assertions) 32/58 (24 inc) 47/58 n/a n/a n/a n/a n/a n/a
Go (29 templates, 58 assertions) 35/58 (22 inc) 45/58 n/a 12/58 (44 uns) n/a n/a n/a n/a
PHP (29 templates, 58 assertions) 32/58 (26 inc) n/a 48/58 12/58 (44 uns) n/a n/a n/a n/a
Ruby (29 templates, 58 assertions) 21/58 (36 inc) 49/58 40/58 12/58 (44 uns) n/a n/a n/a n/a
C++ (28 templates, 56 assertions) 30/56 (26 inc) 42/56 n/a 12/56 (42 uns) n/a 47/56 n/a n/a
C (24 templates, 48 assertions) 40/48 (8 inc) 41/48 n/a 12/48 (34 uns) n/a 43/48 n/a n/a
Rust (27 templates, 54 assertions) 36/54 (18 inc) 44/54 43/54 12/54 (40 uns) n/a n/a n/a n/a

The saturation the preregistration set out to end is still gone. No analyzer
answers a whole expanded core correctly in any of the thirteen languages
,
and no column above reaches its own denominator — including the four new ones,
whose best rows are Infer's 50/58 on Java and OpenTaint's 50/58 on Kotlin,
tied, and both eight short.

The challenge templates stay individually visible as a stratum. The same
populations, restricted to the challenge templates only:

Kernel core Bifrost 0.10.7 CodeQL 2.26.4 Joern 4.0.614 Semgrep CE 1.175.0 OpenTaint Infer v1.3.0 FlowDroid 2.15.1 Pysa 0.10.0
Java (13 templates, 26 assertions) 6/26 (20 inc) 21/26 19/26 0/26 (26 uns) 20/26 20/26 19/26 n/a
JavaScript (13 templates, 26 assertions) 4/26 (22 inc) 19/26 18/26 0/26 (26 uns) n/a n/a n/a n/a
TypeScript (13 templates, 26 assertions) 4/26 (22 inc) 19/26 n/a 0/26 (26 uns) n/a n/a n/a n/a
Python (13 templates, 26 assertions) 4/26 (22 inc) 20/26 20/26 0/26 (26 uns) n/a n/a n/a 18/26
Kotlin (13 templates, 26 assertions) 6/26 (20 inc) 19/26 n/a 0/26 (26 uns) 21/26 n/a 19/26 n/a
Scala (13 templates, 26 assertions) 6/26 (20 inc) n/a n/a n/a n/a n/a n/a n/a
C# (13 templates, 26 assertions) 4/26 (22 inc) 20/26 n/a n/a n/a n/a n/a n/a
Go (13 templates, 26 assertions) 6/26 (20 inc) 19/26 n/a 0/26 (26 uns) n/a n/a n/a n/a
PHP (13 templates, 26 assertions) 6/26 (20 inc) n/a 20/26 0/26 (26 uns) n/a n/a n/a n/a
Ruby (13 templates, 26 assertions) 4/26 (22 inc) 20/26 14/26 0/26 (26 uns) n/a n/a n/a n/a
C++ (12 templates, 24 assertions) 0/24 (24 inc) 14/24 n/a 0/24 (24 uns) n/a 18/24 n/a n/a
C (9 templates, 18 assertions) 10/18 (8 inc) 14/18 n/a 0/18 (18 uns) n/a 15/18 n/a n/a
Rust (12 templates, 24 assertions) 6/24 (18 inc) 16/24 16/24 0/24 (24 uns) n/a n/a n/a n/a

The four new analyzers, and their misses

Published as-is. Each of the four decides every assertion in its cores
definitively — zero inconclusive, zero unsupported, zero runner-error
across all eight of their kernel reports — so every mismatch below is a
measurement of the template's semantic dimension.

OpenTaint (Java, Kotlin) — and the A11 amendment

  • Java 49/58, Kotlin 50/58. Java: 25 true positives, 24 true negatives,
    five false positives, four false negatives. Kotlin: 27 / 23 / six / two.
  • The superseded row, restated rather than removed. The first OpenTaint
    runs read Java 29/58 with 0 reached — every one of the 29 positives
    missed — and Kotlin 38/58 with 17 reached. Those numbers were
    published in the adapter notes and both kernel contracts as a property of
    the pinned engine: a value-kind boundary dropping taint on numeric values,
    isolated by a retained probe.
  • Upstream said that framing was wrong, and it was. Reported as
    seqra/opentaint#388, the
    maintainers identified the boundary as a default rule configuration
    primitive tracking is off unless a rule opts in with
    options: primitive-tracking: true, which the shipped ruleset itself does.
    The claim was verified on the digest-identical jar by a second retained
    probe: with the option absent the original result reproduces exactly, with
    it enabled all four value kinds carry, and the probe's added clean and
    overwrite negatives stay clean.
  • Amendment A11 enables the option in both committed kernel templates.
    That changes the templates' configuration_hash, which invalidated both
    retained reports, and both populations were re-run in full. Java's 29
    positives stop being 29 repetitions of one configuration artifact and become
    29 measurements. The old row is superseded, not hidden: it stands in
    docs/adapters.md's A11 entry, in docs/java-kernel.md, and in
    docs/kotlin-kernel.md, with the probe evidence for both the default and
    the amended configuration retained.
  • What A11 does not do. It moves no case between partitions — the whole
    58-assertion core was scored before and after — and it invalidates no
    published freeze, because neither OpenTaint report had ever been frozen.
  • Where it still misses. Java's four false negatives are exception-catch,
    chal-callback-registration, chal-map-iteration, and
    chal-reflective-invocation; its five false positives are the
    dynamic-heap-location family (array-element-separation,
    chal-computed-property, chal-dispatch-table, chal-element-object) plus
    loop-carried-kill. Kotlin shows the same over-approximation family plus
    chal-function-field, and misses exception-catch and
    chal-reflective-invocation.

Infer v1.3.0 (C, C++, Java)

  • C 43/48, C++ 47/56, Java 50/58, and zero false positives in C++ and
    Java
    — 21 of its 22 mismatches across the three languages are false
    negatives. That is an under-approximating character, and it is the mirror
    image of OpenTaint's and FlowDroid's.
  • Most misses cluster in four families that repeat across languages:
    arithmetic-expression drops (arithmetic-expression-propagation and
    loop-carried-kill, in all three), recursion (chal-recursive-carry, in all
    three), unmodeled collections and registered callbacks
    (chal-callback-registration in all three, chal-map-iteration and
    chal-dispatch-table in C++ and Java), and reflection
    (chal-computed-property in C++ and Java, chal-reflective-invocation in
    Java).
  • Two more are C++ only, and they are the interesting ones:
    chal-closure-capture and exception-catch are false negatives in C++ and
    correct in Java, on the same engine and the same benchmark contract. A
    per-language frontend result, not a semantic one — and the reason Infer's
    cores are three separate populations rather than one pooled row.
  • C's single false positive is dfb-taint-c-dispatch-table-negative, the
    chal-dispatch-table negative, and it is Infer's only over-approximation
    anywhere in this freeze.

FlowDroid 2.15.1 (Java, Kotlin)

  • Java 49/58, Kotlin 49/58, nine mismatches each, and the split is even:
    four false positives and five false negatives in Java, five and four in
    Kotlin.
  • The released CLI analyzes APKs only — verified in the field — so each
    case materializes a minimal APK from pinned, JVM-only pieces: a D8 dex
    translation, a committed benchmark-generated binary manifest, and a harness
    entry activity. That materialization is fixture work, outside the analyzer's
    timed window and outside its measured behaviour.
  • Its false negatives are the higher-order and reflective families:
    chal-callback-registration, chal-dispatch-table, and
    chal-reflective-invocation in both languages, plus chal-closure-capture
    and chal-function-field in Java and chal-computed-property in Kotlin.
  • Its false positives are the same dynamic-heap-location over-approximations
    OpenTaint shows — array-element-separation and chal-element-object in
    both — plus loop-carried-kill in both, chal-computed-property in Java,
    and chal-anonymous-implementation and chal-function-field in Kotlin.
  • Two templates land on opposite sides in the two languages.
    chal-computed-property is a false positive in Java and a false negative in
    Kotlin; chal-function-field is a false negative in Java and a false
    positive in Kotlin. Same analyzer, same template, same benchmark contract,
    opposite errors — which is a language-frontend result, not a semantic one,
    and it is the reason these lists are given per language rather than merged.

Pysa (Python)

  • 47/58, with ten of its eleven mismatches false negatives and one
    false positive (loop-carried-kill) — the most under-approximating row of
    the four, and the widest challenge-stratum gap at 18/26.
  • The pin is a pair: the pyre-check 0.10.0 client drives the separately
    released Pyrefly 1.2.0 front end for call-graph resolution. Without a
    per-case pyrefly.toml, that front end exports every call unresolved
    while exiting cleanly — a verified silent-failure mode that would have
    produced a plausible-looking all-not-reached scorecard. The runner guards
    against it, and the guard is why this row is a measurement rather than an
    artifact.
  • Its misses are almost the whole higher-order and dynamic family —
    chal-anonymous-implementation, chal-callback-registration,
    chal-closure-capture, chal-computed-property, chal-dispatch-table,
    chal-element-object, chal-function-field, chal-reflective-invocation
    plus alias-propagation-separation and exception-catch.

None of the four has a modeling or tool-native report in this freeze.
Those tiers remain the four analyzers of v0.5.0, and the new adapters are
absent from them rather than scored as zero.

First pin-currency review (#92)

The first scheduled review of whether the reference pins are still current,
and the first release in which pins move without any other change. The review
itself — every version witnessed from the installed artifact rather than taken
from a changelog — is recorded in
docs/adapters.md; this
section states what it produced.

Tool v0.5.0 pin v0.6.0 pin Outcome drift
CodeQL 2.26.3 2.26.4 none
Joern 4.0.610 4.0.614 none
Semgrep CE 1.174.0 1.175.0 none
Bifrost 0.10.7 0.10.7 (held) none
OpenTaint, Infer, FlowDroid, Pysa new this cycle evaluated-current at adoption

Zero outcome drift, on the whole shared population. All 2884 case results
that v0.5.0 published are present in v0.6.0 with the identical outcome and
identical classification
— not one moved. The remaining 452 of this freeze's
3336 case results are the four new adapters', which have no v0.5.0
counterpart. Nothing was excluded to reach that number: the intersection is
the whole of v0.5.0.

Every report digest is nonetheless new, and that is not a contradiction.
Normalized reports carry run timestamps and per-case duration_ms, so
re-running a population produces new bytes even when every verdict is
identical. Diffing a report from this freeze against its v0.5.0 counterpart
with those fields set aside gives byte-identical results arrays — plus, for
the three bumped tools, the new tool_version and tool_build_identity. A
reader comparing digest columns across the two releases would otherwise see
"everything changed"; what changed is the run, not the answer.

Bifrost is held at v0.10.7, and the reason is dated. v0.10.8 exists as a
dated version but is not released, so there is no artifact to pin, witness, or
digest. Publishing against an unreleased build of the publishing vendor's own
engine is exactly the thing this benchmark should not do, so the pin stands
and the review records why.

The new adapters are evaluated-current at adoption rather than reviewed
against a previous pin, since they have none. Their pins and witnessed
identities are in the manifest.

First publication: the latency-characterization tier

The tier's contract, docs/latency-tier.md, was preregistered and merged
before any timestamp was captured, for a stated reason: DataFlowBench is
published by the vendor of one of the engines it measures, and a latency page
whose phase boundaries, exclusions, and aggregation were chosen after the
numbers were known would deserve the skepticism it would get.

Amendment A12 (2026-09-01) adds granularity rows for the four adapters
this release introduces. The table is immutable from the moment the first
latency-bearing artifact was retained, and that happened in this cycle, so the
rows are added by dated amendment before this release publishes any number
they describe
— not backfilled into the original table as if they had always
been there. No existing row is edited and no freeze is invalidated.

What was measured

2657 timed analyzer invocations, on one stamped environment:

Hardware model OS OS release Logical CPUs Architecture
Mac16,1 macos 25.6.0 10 aarch64

Run conditions, stated rather than implied: a single developer machine,
under light concurrent load, running the benchmark's standing sequential-run
discipline — one analyzer at a time, never two at once. The discipline is what
makes the numbers usable at all; the light concurrent load is what stops them
being a controlled measurement. These are characterization numbers, good
for order of magnitude and shape, and they are not a micro-benchmark: no
repeated trials, no warm-up, no steady-state harness. Latency numbers are
comparable within one environment and are not comparable across machines.

Whole-invocation wall-clock, per adapter

The only cross-adapter reading the tier supports. Per-case timing at this
granularity includes per-invocation fixed costs — JVM start-up, extractor
initialization, interpreter start — that a long-lived deployment would
amortize; the tier does not correct for that.

Adapter Timed invocations Median Q1 Q3 Min Max Declared phases (median)
Bifrost 0.10.7 883 123 ms 116 ms 133 ms 103 ms 393 ms single invocation
Semgrep CE 1.175.0 196 1.20 s 1.11 s 1.59 s 1.03 s 4.26 s single invocation
FlowDroid 2.15.1 116 1.70 s 1.55 s 1.96 s 1.35 s 3.07 s single invocation
Infer v1.3.0 162 2.21 s 554 ms 6.24 s 468 ms 8.25 s capture 1.78 s, analyze 373 ms
Pysa 0.10.0 58 4.08 s 3.88 s 4.21 s 3.69 s 5.95 s single invocation
OpenTaint 116 4.60 s 4.39 s 4.98 s 3.99 s 10.7 s single invocation
Joern 4.0.614 392 8.70 s 7.18 s 10.1 s 4.48 s 127.9 s single invocation
CodeQL 2.26.4 734 10.8 s 7.22 s 16.7 s 4.39 s 161.0 s database-create 4.51 s, database-analyze 5.58 s

No mean is headlined anywhere, by contract: the distributions are skewed
by per-invocation fixed costs and by long tails, and a mean over that shape
describes neither the typical case nor the tail. The medians span roughly 88×
between the fastest and the slowest, which is the order-of-magnitude claim the
tier is entitled to make and the strongest one it makes.

The granularity is unequal, and it is declared

A phase is timed if and only if the adapter already invokes it as a separate
subprocess
. The benchmark never instruments analyzer internals and never
infers a boundary a subprocess boundary does not expose. So:

  • Two adapters are decomposed. CodeQL exposes database-create and
    database-analyze; Infer exposes capture and analyze. They are the same
    shape: a traced compile, then evaluation-and-emission inside one subprocess.
    CodeQL's database-analyze is query evaluation and SARIF interpretation,
    labelled as containing both — the finer three-way extract/query/
    interpret split would require the CLI's plumbing subcommands, which the
    adapter does not use, and the preregistration named that condition in
    advance rather than after seeing the numbers.
  • Six adapters expose one invocation and take one honestly labelled
    number
    , with JVM or interpreter start-up inside it.
  • Phases compare within an adapter; whole invocations compare across
    adapters.
    A CodeQL database-create number and a Joern total are not the
    same kind of quantity, and nothing published sets them side by side.

Two costs are named so neither is read into a number it is not in.
FlowDroid's per-case APK materialization is excluded — the D8 dex
translation and the APK assembly happen before the timed subprocess is
spawned, so FlowDroid's 1.70 s is analyzer wall-clock, not the cost of getting
a case in front of FlowDroid. Pysa's front-end cost is inside its one
number
— the client drives Pyrefly and the analysis within a single
invocation, so that boundary is not adapter-observable and was not guessed at.

What has no latency number, and why it is not zero

679 bound case results carry no timing, and every one of them is
unsupported
: decided from case metadata before the analyzer is invoked, so
there is no subprocess to time. They are absent from every distribution, not
entered as zero
— entering them as zero would make the adapters that decline
the most look the fastest, which is exactly backwards. Every case that did
invoke an analyzer is timed; timed plus untimed accounts for the whole bound
population with no remainder.

What the freeze does and does not guarantee here

The publication gate is the manifest's bound case set: the site reads a timing
sidecar only when reports/freeze.json binds that report and that case, so a
sidecar left in the tree by an unbound run cannot reach a published number.

But freeze/v1 binds one raw-evidence digest per result, and the timing
sidecars and environment stamps are additive files beside that evidence — the
manifest does not digest them. A latency number here therefore carries the
freeze's guarantee that the run it belongs to is bound and byte-verified, plus
the release commit's immutability for the timing bytes, and not a manifest
digest over those bytes. Extending the manifest to bind them is a freeze/v2
question; it is named rather than smuggled in under a schema version that does
not describe it.

Latency is never pooled with correctness, anywhere: no combined number, no
efficiency-adjusted rate, no blended ranking. No correctness outcome in this
freeze was derived from, conditioned on, or tie-broken by a timing value, and
the tier's page stands beside the scorecards rather than as a column inside
one.

The other tiers, unchanged

The modeling and tool-native tiers reproduce v0.5.0 exactly — same four
analyzers, same scored partitions, same cells — and are restated here only
because this freeze rebinds them at new pins.

  • Benchmark-controlled modeling. CodeQL enters all six categories and
    answers all 72 of its assertions correctly. Joern is 14/16 with two false
    negatives per language, both category B, and eight unsupported under
    Amendment A2. Semgrep CE is 10/10 on five templates with 14 unsupported,
    its sanitizer-selectivity decline recorded as Amendment A3. Bifrost enters
    two of six categories after Amendment A9: java and python 8/8, javascript
    5/8 with three inconclusive and no mismatch, beside 48 unsupported.
  • Tool-native. CodeQL is the only adapter with a shipped model that
    decides across all three languages (11/12 java, 9/12 javascript, 10/12
    python). Semgrep CE decides python 8/12 off a shipped audit rule (Amendment
    A8) and declines java and javascript entirely (A7, A6). Joern and Bifrost
    decline all twelve in every language, with run identity witnessed anyway
    (Amendment A10 for Bifrost's category-Z cell). Zero of twelve is not a
    score of zero
    — all twelve are unsupported, which is declared coverage.
  • language-extension tiers stay outside every core denominator: on C's
    two cases CodeQL is 2/2 and Bifrost 1/2 with one inconclusive; on Rust's
    Result/? pair CodeQL is 1/2 and Bifrost inconclusive on both.

Honest negatives carried forward

  • Bifrost's four false positives from v0.5.0 are still here, unchanged:
    dfb-taint-csharp-infeasible-branch-negative,
    dfb-taint-csharp-loop-carried-negative,
    dfb-taint-go-loop-carried-negative, and
    dfb-taint-ruby-infeasible-branch-negative, filed as
    BrokkAi/bifrost-dev#2731. The pin did not move, so neither did they.
  • The Java direct-propagation instability persists, unreconciled, for the
    third release running.
    dfb-taint-java-direct-positive is still reached
    in reports/bifrost-smoke.json and not-reached in
    reports/bifrost-java-kernel.json, at the same fixture revision and the
    same build. Both raw artifacts are retained and digest-bound, and neither
    was re-run to agreement.
  • Bifrost's 298 core inconclusive results are unchanged and still
    concentrated: Ruby 36 of 58, Kotlin 30, PHP and C++ 26 each, C# and
    TypeScript 24 each; lightest is C at 8 of 48. Declines, not misses — but on
    a page where seven other analyzers now decide these same cases definitively,
    the shape of that column is more visible than it has ever been, and it
    should be.

A freeze-time find: JSON Lines raw evidence (#103)

Found while assembling this freeze, and recorded because a fix made under
release pressure is exactly the kind that should be visible. create-freeze
refused the Pysa kernel's raw artifacts with "trailing characters at line
2"
: Pyre's taint output is JSON Lines — a version header plus one record
per line — retained verbatim per the house convention, while the freeze's
raw-evidence parse assumed one JSON document per file. The collision only
surfaced now because Pysa post-dates the v0.5.0 freeze.

That parse exists solely for the incompletes-never-negatives audit
(raw_special_outcome), the check that stops an inconclusive or
runner-error raw artifact being published behind a clean not-reached. The
fix keeps the audit at full strength over both shapes: try a
single-document parse, fall back to a document stream, and flag a special
outcome if any document declares one. Empty and non-JSON content still
error. No report bytes, no schema, and no runner behaviour changed — the
evidence was already assembled when the defect was found.

Amendments recorded this cycle

  • A11 (2026-08-31) — OpenTaint's value-kind boundary is a default rule
    configuration, and primitive tracking is enabled in both kernel templates.

    Recorded in docs/adapters.md. Upstream-guided, verified on the
    digest-identical jar, partition-inert, and it supersedes a published row
    that remains in the record.
  • A12 (2026-09-01) — the four adapters added in v0.6.0 take their latency
    granularity rows.
    Recorded in docs/latency-tier.md. Dated and landed
    before the first publication of any number it describes; invalidates no
    freeze.

Amendments A1 through A10 remain in force and are unaffected.

Bound evidence

Normalized report SHA-256 Analyzer Cases
reports/bifrost-c-kernel.json 8148bfd8f2b9f0b0155dab3b0301d00612aef085dc330a6a2a2aeb8fc29e9662 Bifrost 0.10.7, build 44d9a5be416432bf8ed414afd3ea0031245ebb57 50
reports/bifrost-cpp-kernel.json 13995907b4422092021c89981fbbb4f923250f2cff4ddbfa7dd8d6c804c9d46e Bifrost 0.10.7, build 44d9a5be416432bf8ed414afd3ea0031245ebb57 56
reports/bifrost-csharp-kernel.json fba07c6c710dba02d5a94bc1f0bae253a2640db4f58a20cf866f5ba7c7f73625 Bifrost 0.10.7, build 44d9a5be416432bf8ed414afd3ea0031245ebb57 58
reports/bifrost-go-kernel.json 010ac34f973a976371a81968484b885eb1cd47ec2a6b10679de24a3abcbcb260 Bifrost 0.10.7, build 44d9a5be416432bf8ed414afd3ea0031245ebb57 58
reports/bifrost-java-kernel.json 1cf243b3b656afc870794459ca8a8a68d00d0d8beaeb516b07b249cd9a0d905c Bifrost 0.10.7, build 44d9a5be416432bf8ed414afd3ea0031245ebb57 58
reports/bifrost-java-modeling.json e3826115c7c9630c787701b41fb1310230838841bf065d62afdc16f601ee9ae6 Bifrost 0.10.7, build 44d9a5be416432bf8ed414afd3ea0031245ebb57 24
reports/bifrost-java-native.json 1958c07c4a2f378ac520f45ddf14f738736353c6728904852728dafd43a513b2 Bifrost 0.10.7, build 44d9a5be416432bf8ed414afd3ea0031245ebb57 — bifrost 0.10.7 built-in policy packs 12
reports/bifrost-javascript-kernel.json ae46adf16ba81276c224efa700f1b7cd27dd36cd92fac178256f03c0dbee8208 Bifrost 0.10.7, build 44d9a5be416432bf8ed414afd3ea0031245ebb57 58
reports/bifrost-javascript-modeling.json e9919e1dbc309cc26e7797e0168401beef46b95848af0ecfb9f1f2f056d00c34 Bifrost 0.10.7, build 44d9a5be416432bf8ed414afd3ea0031245ebb57 24
reports/bifrost-javascript-native.json 79002ce778c6e008e62076768639e593a05d0f40c2668f40bd48b18373993562 Bifrost 0.10.7, build 44d9a5be416432bf8ed414afd3ea0031245ebb57 — bifrost 0.10.7 built-in policy packs 12
reports/bifrost-kotlin-kernel.json 5015b8561bcf114af5a115a91320782406fba2a0e5fe2fb9f96a5518f3e98c89 Bifrost 0.10.7, build 44d9a5be416432bf8ed414afd3ea0031245ebb57 58
reports/bifrost-php-kernel.json 39bb8476a9bf1d20cc716f4f384f03a94b663130afbf6370136aa15a87486815 Bifrost 0.10.7, build 44d9a5be416432bf8ed414afd3ea0031245ebb57 58
reports/bifrost-python-kernel.json ea4d22001898550fc4791360e793eed77d4d927a77451e7fb50d02633e22be9f Bifrost 0.10.7, build 44d9a5be416432bf8ed414afd3ea0031245ebb57 58
reports/bifrost-python-modeling.json 7c60420cf77a827a448f41977b4d083e492e6a9fd9809d186774f54adf5d13e9 Bifrost 0.10.7, build 44d9a5be416432bf8ed414afd3ea0031245ebb57 24
reports/bifrost-python-native.json 005c3ea542b2fcd5a7e5f78e36140cca736f91778f4eb35c419f335c7cfdadc3 Bifrost 0.10.7, build 44d9a5be416432bf8ed414afd3ea0031245ebb57 — bifrost 0.10.7 built-in policy packs 12
reports/bifrost-ruby-kernel.json 0c20d8e951de0675671f9da3f62ebb96c71820210b186c8ac775e2cfddb0d7ae Bifrost 0.10.7, build 44d9a5be416432bf8ed414afd3ea0031245ebb57 58
reports/bifrost-rust-kernel.json 633c21813ff38d24bc9b5c73acdc71608b43bdafb281a673e4722d692c187a4e Bifrost 0.10.7, build 44d9a5be416432bf8ed414afd3ea0031245ebb57 56
reports/bifrost-scala-kernel.json 992a0bc3467cc9192d56e7040b703bb9dbcd645ae8b99eb6f1c13581f4d7e52b Bifrost 0.10.7, build 44d9a5be416432bf8ed414afd3ea0031245ebb57 58
reports/bifrost-smoke.json 1e123684a11d684df2b07fbc6e109e81c91080034abccfa4f1d019b08d1c7482 Bifrost 0.10.7, build 44d9a5be416432bf8ed414afd3ea0031245ebb57 118
reports/bifrost-typescript-kernel.json 1bfa7b0604d85f63768f3f9c6862f5a44a7a4e962aca5ac75b5c9899dc8b7624 Bifrost 0.10.7, build 44d9a5be416432bf8ed414afd3ea0031245ebb57 58
reports/codeql-c-kernel.json 0bbf4766f6a5fe4a60cbc1fdf6667b942a01456df9c0828485db8d43b201fd4d CodeQL 2.26.4, build codeql-cli:6b1e4dee94adb20f90a671f3fc9e04be32eecf65 50
reports/codeql-cpp-kernel.json f314c4185eae8ef7f33feeee76b7c124cc4aef8684c923197bacb19e5190a9a8 CodeQL 2.26.4, build codeql-cli:6b1e4dee94adb20f90a671f3fc9e04be32eecf65 56
reports/codeql-csharp-kernel.json 313b44a93327652b642893d58ad55283d1cababbf5c92e147e1281bf93ce5d66 CodeQL 2.26.4, build codeql-cli:6b1e4dee94adb20f90a671f3fc9e04be32eecf65 58
reports/codeql-go-kernel.json 99dc5a3c7c17b27471028afd359830f8ee7fb51f1875c8fee1981d95826fa33d CodeQL 2.26.4, build codeql-cli:6b1e4dee94adb20f90a671f3fc9e04be32eecf65 58
reports/codeql-java-kernel.json 50418965ee291047161e4fe06d5c765f2f0fad492d6288c585be047276677ddc CodeQL 2.26.4, build codeql-cli:6b1e4dee94adb20f90a671f3fc9e04be32eecf65 58
reports/codeql-java-modeling.json 14c991ee939e1d4aef3e2850551166cfc3d5de606919aa186a577e4938100975 CodeQL 2.26.4, build codeql-cli:6b1e4dee94adb20f90a671f3fc9e04be32eecf65 24
reports/codeql-java-native.json 5d7d7b152c9366525b8362438cc83a8c0cf6008b519a9c84f200eca711acee31 CodeQL 2.26.4, build codeql-cli:6b1e4dee94adb20f90a671f3fc9e04be32eecf65 — 2.26.4 shipped suite codeql/java-queries@1.11.9:codeql-suites/java-security-extended.qls 12
reports/codeql-javascript-kernel.json 78ad35bbf7886d47461940128a622540ea4de94001406ba2f0431de48c7763c9 CodeQL 2.26.4, build codeql-cli:6b1e4dee94adb20f90a671f3fc9e04be32eecf65 58
reports/codeql-javascript-modeling.json 3a908bdc80fb84d2be7c47c75edce0950b688a71342137b8f70b98aa0359311f CodeQL 2.26.4, build codeql-cli:6b1e4dee94adb20f90a671f3fc9e04be32eecf65 24
reports/codeql-javascript-native.json bd5fe87f32f7fc30ea5deb365de613d2d49b5db3db57dbe724fc8625007d6db6 CodeQL 2.26.4, build codeql-cli:6b1e4dee94adb20f90a671f3fc9e04be32eecf65 — 2.26.4 shipped suite codeql/javascript-queries@2.4.4:codeql-suites/javascript-security-extended.qls 12
reports/codeql-kotlin-kernel.json ee7720f6d318834d2f01ecbdeab946cd5ae089cb70a1ffb3f39207259d442fa7 CodeQL 2.26.4, build codeql-cli:6b1e4dee94adb20f90a671f3fc9e04be32eecf65 58
reports/codeql-python-kernel.json cd304f94b4d9af5050a8228ff96c4b530fadef1af294b7e59a2855c47b6bab6c CodeQL 2.26.4, build codeql-cli:6b1e4dee94adb20f90a671f3fc9e04be32eecf65 58
reports/codeql-python-modeling.json 60ff9613a8e5deedd2c1b3f787911ce6fdb94430c3caaa34eb724695b82bcd4e CodeQL 2.26.4, build codeql-cli:6b1e4dee94adb20f90a671f3fc9e04be32eecf65 24
reports/codeql-python-native.json 2958f4e44c4075463079503bd7c222860076fc159475f76532a258f1aa0bf49e CodeQL 2.26.4, build codeql-cli:6b1e4dee94adb20f90a671f3fc9e04be32eecf65 — 2.26.4 shipped suite codeql/python-queries@1.8.9:codeql-suites/python-security-extended.qls 12
reports/codeql-ruby-kernel.json 10fb9cc1a8d2bfdd7405f7828045217cac00be4951d1e22a3c75e35e46eebcab CodeQL 2.26.4, build codeql-cli:6b1e4dee94adb20f90a671f3fc9e04be32eecf65 58
reports/codeql-rust-kernel.json b98733c392bcbca66953bb6fa779232676174c4e07c5fdaadaf3bcd94173082f CodeQL 2.26.4, build codeql-cli:6b1e4dee94adb20f90a671f3fc9e04be32eecf65 56
reports/codeql-typescript-kernel.json 49eaacb9cf7e5bdb6e49a4b8527885c2ca94c40bffe6df7d4c70f8e1187d4017 CodeQL 2.26.4, build codeql-cli:6b1e4dee94adb20f90a671f3fc9e04be32eecf65 58
reports/flowdroid-java-kernel.json df7fbd5263d3d27d95ce4da36688c8d5050dd3844a6096ee258d67f4c3f3ba83 FlowDroid 2.15.1, build soot-infoflow-cmd-2.15.1-jar-with-dependencies.jar sha256:51dadead47a173c494c2fa4855b1e8bd3b54e702a2c4b5ed58e60153009ae218; android-34 platform android.jar sha256:6cea1df3efb77103ac3e2beb9bf4718964b0e0869ab16d39d29d5cbae1c147ad; dexed by D8 8.5.35 (build 2c176ec131a9edb97721fb8578b7fbb462376632 from go/r8bot (luci-r8-custom-ci-archive-0-gths)); r8 jar sha256:4733945987ee0a840fafc34080b135259e01678412e07212b23f706334290294 58
reports/flowdroid-kotlin-kernel.json 44bb26f4541c5d42b3be8cab06d47a7f29775bf273998f038166639489e66634 FlowDroid 2.15.1, build soot-infoflow-cmd-2.15.1-jar-with-dependencies.jar sha256:51dadead47a173c494c2fa4855b1e8bd3b54e702a2c4b5ed58e60153009ae218; android-34 platform android.jar sha256:6cea1df3efb77103ac3e2beb9bf4718964b0e0869ab16d39d29d5cbae1c147ad; dexed by D8 8.5.35 (build 2c176ec131a9edb97721fb8578b7fbb462376632 from go/r8bot (luci-r8-custom-ci-archive-0-gths)); r8 jar sha256:4733945987ee0a840fafc34080b135259e01678412e07212b23f706334290294 58
reports/infer-c-kernel.json 35a5f9de818f815fb4b682643a3f0f512784043ac0962c4c6e30e05abe19110c Infer v1.3.0, build infer:v1.3.0 bin-sha256:17ed4818dadda60124e083a1e82124f104092e70c5e6d764551581a375eabf62 48
reports/infer-cpp-kernel.json fc3b5fd70a89dbe9bd400c3a1f7d8eaf44f461fd02a1f3cf19264ec67cd98199 Infer v1.3.0, build infer:v1.3.0 bin-sha256:17ed4818dadda60124e083a1e82124f104092e70c5e6d764551581a375eabf62 56
reports/infer-java-kernel.json 9eb9d7ce745f88bf2e6eed406de14201ccc4db8e592a1c501f7294cca590bdf4 Infer v1.3.0, build infer:v1.3.0 bin-sha256:17ed4818dadda60124e083a1e82124f104092e70c5e6d764551581a375eabf62 58
reports/joern-java-kernel.json 8f74bb4d958ba21cfc236a9382b4b67a09fc5ebfd16d71b7e8bc3a112f7b722e Joern 4.0.614, build joern-cli:4.0.614 58
reports/joern-java-modeling.json 21fb1d444a2db6dd5dbd8c1aba56abd2d728a1aa616f049a417ebc73e3fee7d8 Joern 4.0.614, build joern-cli:4.0.614 24
reports/joern-java-native.json a438c1ecdc09f23db4cdb14dea45fc99ba6658af4d9d887c9d7852e5d2ac2aa8 Joern 4.0.614, build joern-cli:4.0.614 — 4.0.614 DefaultSemantics only 12
reports/joern-javascript-kernel.json 9f54af854f6b0cdc864b8017c2ccd3ad9f3b2cf952e2376b4c988c60e90e9462 Joern 4.0.614, build joern-cli:4.0.614 58
reports/joern-javascript-modeling.json cd6372a8fc9b462a51a460e23d344103bae384fe92cbe4e37ce641686c265d36 Joern 4.0.614, build joern-cli:4.0.614 24
reports/joern-javascript-native.json b8f493cdb3761d9ee676bfac80ba0b83377750ef970d2d845a06107d4987ee44 Joern 4.0.614, build joern-cli:4.0.614 — 4.0.614 DefaultSemantics only 12
reports/joern-php-kernel.json 153d0fb50e2cbe7241aaf7eb6d1a5a5b092fb11c39bf9d0bdfc54838608bb4ed Joern 4.0.614, build joern-cli:4.0.614 58
reports/joern-python-kernel.json 811b6d11d5f9ecde11d4c1c35bef55efb62799984dce9ecc08a46317fd0ff50a Joern 4.0.614, build joern-cli:4.0.614 58
reports/joern-python-modeling.json 3e05499c361b7cf797281ab94cb5cc655d5ce306430a95b396f99c7b0f851e75 Joern 4.0.614, build joern-cli:4.0.614 24
reports/joern-python-native.json d7015cc6c9b14ee41ba7c05f547909c8b67a48df076d76c00758401ae4fb296e Joern 4.0.614, build joern-cli:4.0.614 — 4.0.614 DefaultSemantics only 12
reports/joern-ruby-kernel.json 9f2b18c4d168a3bf1b1c8c2adf885ac7416e247081a366980f144a683a27ea3b Joern 4.0.614, build joern-cli:4.0.614 58
reports/joern-rust-kernel.json 465269d73a072957b318fdac73768d5e4fb538ff9f3e31c007f88f6c96bcf055 Joern 4.0.614, build joern-cli:4.0.614 54
reports/opentaint-java-kernel.json de32158291e6ddb9e10f728aba7b2d2a3a39806fb4fa4870f8c27d9f97fbf7db OpenTaint analyzer/2026.08.27.17eb0fe, build opentaint-project-analyzer.jar sha256:811bdb22786e539c9aabdce5bef91f0c6521cc099adbe2720e6a840c09badf54; opentaint-models.tar.gz sha256:c2a8fb0bbc3b6d59ed6db0c62732ff9a6f0f491d515cc2247932f2dd78cbb9f5 58
reports/opentaint-kotlin-kernel.json 1fb872fea820eff6854141f77d883ef1312e1d498b0c4e850cbbe4788ce616ea OpenTaint analyzer/2026.08.27.17eb0fe, build opentaint-project-analyzer.jar sha256:811bdb22786e539c9aabdce5bef91f0c6521cc099adbe2720e6a840c09badf54; opentaint-models.tar.gz sha256:c2a8fb0bbc3b6d59ed6db0c62732ff9a6f0f491d515cc2247932f2dd78cbb9f5 58
reports/pysa-python-kernel.json 125faf9d9127b71b9b0d2b0d55229bdd26136c0e151fc2c2f555abcf500d609a Pysa 0.10.0, build pyre-check:0.10.0 pyre.bin-sha256:035a206349193dafdac70ec4020a992add5d88e60dee76163cf39ffb0b8fe8a3 pyrefly:1.2.0 pyrefly-sha256:6b460273720d857142be562d2c0c607e8ed8e5e752ab575b5c00ea3f735d8caa 58
reports/semgrep-c-kernel.json 5192f0b66650605bdbba4e1ec3e4d0e2da232490bdaca08a14434737dfb9bdc4 Semgrep CE 1.175.0, build semgrep-oss:1.175.0 48
reports/semgrep-cpp-kernel.json 40de77a28a692227d8081c113ef6b39a6c237da73aff74c7daee77a3b6f0544b Semgrep CE 1.175.0, build semgrep-oss:1.175.0 56
reports/semgrep-go-kernel.json 77d87ca7eee69d7b1384f0d09a32d82c7d5823023875d651c46338275906e961 Semgrep CE 1.175.0, build semgrep-oss:1.175.0 58
reports/semgrep-java-kernel.json 05ab32127cb788dd2b6d844015c00852a0c32cb50db6b8d5587a59cfbaa67189 Semgrep CE 1.175.0, build semgrep-oss:1.175.0 58
reports/semgrep-java-modeling.json 94a5eda43ab2aab5ab47b44e80907ab18dd4796a2f2a364bbac621d45cd19c63 Semgrep CE 1.175.0, build semgrep-oss:1.175.0 24
reports/semgrep-java-native.json f20ab62be7d8d3e4a6678ac07041d691b36d53ea66d8bb1c44fce4182dbb71d0 Semgrep CE 1.175.0, build semgrep-oss:1.175.0 — 1.175.0 over the pinned snapshot vendored from https://github.com/semgrep/semgrep-rules into adapters/semgrep/native/java 12
reports/semgrep-javascript-kernel.json ae4527e7a74c5d8f51d9549db95bd271b12f672a6d39f86adb71d4f9353f21f3 Semgrep CE 1.175.0, build semgrep-oss:1.175.0 58
reports/semgrep-javascript-modeling.json 5745951d82b9dacfb339ecc9aeb44af4975bf1162428b3a3d76cfb3e096739a7 Semgrep CE 1.175.0, build semgrep-oss:1.175.0 24
reports/semgrep-javascript-native.json 249bd7e020955ab8f181a04ce1b257fb4a72ed93ac7d4eabaec0b572331db0ac Semgrep CE 1.175.0, build semgrep-oss:1.175.0 — 1.175.0 over the pinned snapshot vendored from https://github.com/semgrep/semgrep-rules into adapters/semgrep/native/javascript 12
reports/semgrep-kotlin-kernel.json 3fd452bdb1b7ad0f2d310952bf04f64a1245e70cfef2e4f49c735d1798fd114e Semgrep CE 1.175.0, build semgrep-oss:1.175.0 58
reports/semgrep-php-kernel.json b04ee7111c66f3cab105ae0bf992495f59e86faf7153f08890a16650f712923e Semgrep CE 1.175.0, build semgrep-oss:1.175.0 58
reports/semgrep-python-kernel.json 6341e3f6321e2fa53b352f1a9afe39665ae4284190f2ab7257c709a23e952648 Semgrep CE 1.175.0, build semgrep-oss:1.175.0 58
reports/semgrep-python-modeling.json a269705d853a642979a357b9a03fd698cf2bc3e853c9afff1513e9c4b0001086 Semgrep CE 1.175.0, build semgrep-oss:1.175.0 24
reports/semgrep-python-native.json a0187f8a2fb1212c516ddf3095ee347f47e82eeaeb9c9a98dad1c58e513c8216 Semgrep CE 1.175.0, build semgrep-oss:1.175.0 — 1.175.0 over the pinned snapshot vendored from https://github.com/semgrep/semgrep-rules into adapters/semgrep/native/python 12
reports/semgrep-ruby-kernel.json deae3cd4a04bc9dbf9f5fb1d6e2d0c8dbdefd0e2b9c561a9f7544ce130097529 Semgrep CE 1.175.0, build semgrep-oss:1.175.0 58
reports/semgrep-rust-kernel.json 7b93011a586b390a0a212af70653b0c52a20dc1c535b5d9c1c78ac3ff14b36e7 Semgrep CE 1.175.0, build semgrep-oss:1.175.0 54
reports/semgrep-typescript-kernel.json 691658e531af76e919e418700e60067501e6a494f4057af36520b0d04b6a5ee6 Semgrep CE 1.175.0, build semgrep-oss:1.175.0 58

Every report remains its own scorecard. The build identity column is the
witnessed identity of the binary actually invoked, extended for the native
rows with the shipped ruleset or pack that was activated — including the rows
that decide nothing. Raw evidence for every result is retained under
reports/raw/ and digest-bound in the manifest; per-case timing sidecars and
per-run environment stamps sit beside it as additive metadata.

Reproduction

git checkout v0.6.0                # frozen benchmark revision (evidence commit)
# then check out the merge commit carrying reports/freeze.json for this release
cargo run -- validate-freeze reports/freeze.json
cargo run -- generate-results --manifest reports/freeze.json --output-directory results --check

Adapter re-execution (produces new evidence, therefore a new freeze) follows
the same shape as v0.5.0's for Bifrost, CodeQL, Joern, and Semgrep CE. The
four new adapters:

cargo run -- run-opentaint-java-kernel \
  --analyzer-jar <opentaint-project-analyzer.jar> \
  --models-archive <opentaint-models.tar.gz>
cargo run -- run-opentaint-kotlin-kernel \
  --analyzer-jar <opentaint-project-analyzer.jar> \
  --models-archive <opentaint-models.tar.gz> \
  --kotlin-stdlib <kotlin-stdlib.jar>

cargo run -- run-flowdroid-java-kernel \
  --flowdroid-jar <soot-infoflow-cmd-2.15.1-jar-with-dependencies.jar> \
  --android-platform <android-34/android.jar> --d8-jar <r8.jar>
cargo run -- run-flowdroid-kotlin-kernel \
  --flowdroid-jar <soot-infoflow-cmd-2.15.1-jar-with-dependencies.jar> \
  --android-platform <android-34/android.jar> --d8-jar <r8.jar> \
  --kotlin-stdlib <kotlin-stdlib.jar>

for kernel in c cpp java; do
  cargo run -- run-infer-$kernel-kernel --infer <infer-binary>
done

cargo run -- run-pysa-python-kernel --pyre <pyre-binary> \
  --pyre-binary <pyre-analysis-binary> --pyrefly <pyrefly-binary>

The FlowDroid runners materialize a minimal APK per case and therefore need a
JVM, the D8 dex translator, and an Android platform jar; the released CLI
analyzes APKs only. The Pysa runner requires both halves of its pin — the
pyre-check client and the separately released Pyrefly front end — and writes a
per-case pyrefly.toml, without which the front end reports every call
unresolved while exiting zero.

Immutability

This snapshot is immutable. Corrected evidence creates a new freeze with a new
release name and digests; the v0.1.0 through v0.5.0 manifests and evidence
remain available at their release commits for audit. This release has no DOI
and no external review claim.