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 — 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"}.
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 — 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

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 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.