The Occurrence
AnOccurrence is one sighting of a component by one detector — the answer to “why is this in
my AIBOM?”.
Location
Where the evidence physically sits.
path is always set, source-root-relative with forward
slashes. line / endLine are 1-based (0 means whole-file). column / endColumn are
1-based UTF-16 code units. layer carries the OCI layer digest when the sighting is
attributable to one.string
Stable detector identifier, e.g.
rules/openai/model-literal. This is the SARIF ruleId.DetectionMethod
How this sighting was made — one of the eight methods below. The method is a property of the
sighting, not of the detector: one detector can report different methods for different files.
dataset/file reports binary-analysis for a Parquet file it confirmed by magic bytes, and
filename for a .csv it recognized by extension alone.number
Belief in [0,1] for this sighting alone. Not the component’s confidence — see
confidence for how the engine combines them.
string
The matched text. Capped at 200 bytes and sanitized.
string
The enclosing function or class, when known.
map[string]string
Extracted bindings from the match, e.g.
{"model": "gpt-4.1", "temperature": "0.2"}.Occurrence counts in table output
Contested identity is kept
Two detectors can disagree. A version read from a lockfile and a version read from a code comment are both real observations of the codebase — and the losing one is the interesting one, because a mismatch between a lockfile and a comment is exactly what you want to see. AIROM never silently drops the loser. Each contested field is preserved as anIdentityClaim:
string
One of
name, version, purl, hash. These are a strict subset of the CycloneDX identity
field enum.string
The claimed value.
number
Belief in this specific claim.
DetectionMethod[]
The methods that support the claim.
version. Every claim — winner
included — is retained in evidence.identity[].
A version from a lockfile (0.95) beats one from a code comment (0.3). The comment’s claim stays
in the AIBOM as a competing identity entry. Nothing is discarded to make the output look tidy.
The 8 detection methods
Methods are named to align with the CycloneDX evidence technique enum by design: seven of the eight are the identical string, so the CycloneDX writer is nearly a cast rather than a translation table.config-analysis is the sole exception.
config-analysis is the one method with no same-named CycloneDX enum value, so it maps to
other and sets a recovery marker (methods[].value: "config-analysis") — the exact method is
always recoverable from the emitted document. The CycloneDX values instrumentation and
dynamic-analysis are reserved for a future runtime-probing mode and are never emitted today.hash-comparison is the only v1 method that can assert certainty; attestation is the v2 path
to the same. Every other method is capped. See confidence.
How evidence projects into each format
- Native (json / yaml)
- CycloneDX
- SARIF
Lossless.
evidence.occurrences[] and evidence.identity[] in full, plus relationship
evidence — the call sites proving each edge. The native formats are the only place edge
evidence survives.Full-fidelity output
These three are the only projections there are:
table reports each component’s primary
path:line and an occurrence count (--wide expands the full list). SPDX is not an output format today — the SPDX 3.0.1 AI profile is reserved for
v2, and it has no model for evidence, so evidence will remain a native / CycloneDX / SARIF
property when it lands.Reading the evidence
The fastest way to audit a surprising component is SARIF: every occurrence becomes a result pinned atfile:line, which most editors and code-scanning UIs will jump to directly. For
scripted inspection, the native JSON keeps everything, including the detector ID per occurrence.
Confidence
How occurrences combine into a component-level score.
What is an AIBOM
The 13 component kinds and what each one carries.