An AIBOM you cannot audit is a list of guesses. AIROM’s answer is the occurrence: every component in the inventory carries the sightings that put it there, each anchored to a path, a line, a snippet, and the detector responsible. The rule is simple. If AIROM cannot point at the thing, AIROM does not claim the thing.

The Occurrence

An Occurrence is one sighting of a component by one detector. It answers “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, using 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. This is 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"}.
A component with twelve occurrences was seen twelve times. The table output reports that count directly:
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 an IdentityClaim:
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.
The highest-confidence version claim becomes the component’s version. Every claim is retained in evidence.identity[], including the winner.
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"), so 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

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 evidence-bearing projections: table reports each component’s primary path:line and an occurrence count (--wide expands the full list). AIROM also writes SPDX 3.0.1, but SPDX has no model for an occurrence, so no file:line evidence survives into it. Each package states its occurrence count and nothing more. Evidence remains a native, CycloneDX and SARIF property.

Reading the evidence

The fastest way to audit a surprising component is SARIF: every occurrence becomes a result pinned at file: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.