This document tracks every place where the k8s-aibom BOM output deviates from, or extends, the CycloneDX 1.6 ML-BOM specification or established conventions (notably the Trusera/ai-bom project's choices). Each divergence has a rationale, an example, and a link to the upstream issue or discussion where applicable. Per PRD §9.4, divergences must be documented so design partners and CycloneDX maintainers can audit them.
Active register, seeded 2026-09-28 from the shipped v1.5.x output. Entries below cover the divergence families the emitter actually produces; per-field additions land as consumers raise them. This register is the companion to any schema conversation with CycloneDX upstream (see the 2.0 RFC comments on CycloneDX/specification#990).
Status: active
What we do: every attribute-bearing component carries
aibom.confidence (declared | inferred | unresolved | verified),
aibom.evidence.locator (the exact spec field the fact came from,
e.g. spec.template.spec.containers[0].args[1]) and
aibom.evidence.source, plus workload identity properties
(aibom.workload.*) and controller provenance
(aibom.controller.*).
What the spec says: CycloneDX 1.6 has components[].evidence
with identity confidence for software components, but its
methods vocabulary has no runtime-observation or
signature-verification technique, and model components (ML-BOM)
have no evidence surface at all.
Why we diverge: auditors need per-attribute confidence and a
pointer to the exact source; properties are the sanctioned
extension mechanism. Proposed upstream: a signature-verification
identification technique (spec#990 comment) and official
ai:runtime:* names (property-taxonomy#175).
Status: active
What we do: model components carry signature.status
(unsigned | claimed | verified), signature.outcome (including
signature-valid-unconstrained), signature.reason,
signature.identity, signature.rekorEntry,
signature.subjectNameMismatch.
What the spec says: 1.6 has no representation for "a runtime
verifier checked this model's signature against an operator trust
root"; attestation semantics cover party assertions, not direct
verification.
Why we diverge: the verified tier is meaningless without its
facts being inspectable; collapsing "valid signature, unconstrained
signer" into "verified" would launder identity (Design 002 §5).
Status: active What we do: when the output sanitization pass redacts credential material, the document says so — a fact, never a silent omission. Why we diverge: an auditor must be able to distinguish "value absent" from "value removed"; the spec has no redaction marker.
Status: active
What we do: container components carry the observed reference
and tag as properties alongside the digest in hashes[].
Why we diverge: the digest is the identity; the mutable
reference is evidence context. purl emission (pkg:oci) is planned
(roadmap, v1.7 candidates) and will supersede part of this entry —
tracked here so the byte-determinism change ships changelog-led.
Each divergence entry should follow this template:
### D-NNN: <short title>
**Status:** active | rescinded | upstreamed
**Introduced in:** <version or commit>
**Spec section:** <CycloneDX section reference>
**Trusera comparison:** <same / different / not covered>
**What we do**
<concrete description of the encoding the controller emits>
**What the spec says (or doesn't)**
<quote or paraphrase the spec; note where it's silent>
**Why we diverge**
<the rationale — usually customer/auditor requirement or spec ambiguity>
**Upstream tracking**
<link to CycloneDX issue, RFC, or maintainer thread, if any>
**Example BOM fragment**
\`\`\`json
{ ...minimal illustrative excerpt... }
\`\`\`
The following divergences are already decided in design and will be filled in as the corresponding code lands.
-
D-001: Signature confidence tiering. v1 reports OMS signatures as one of
unsigned/claimed/verified, encoded via CycloneDXevidence.identity.methods[].confidence. v1 will never emitverifiedbecause v1 does not perform Rekor lookup or artifact verification. Auditors reading a v1 BOM can trustclaimedto mean "we saw an annotation or attestation reference but did not validate it cryptographically." See PRD FR2.5 and theinternal/scraperSignatureVerifier interface (withNoopVerifierv1 implementation;RekorVerifieris the v2 plug-in point). -
D-002: Per-attribute evidence sourcing. Every BOM attribute carries metadata identifying the specific source it was extracted from (
pod_annotation,container_arg,env_var,image_pattern,crd_field,volume_source,node_selector, etc.). This is in addition to (not a replacement for) workload-leveldeclared/inferredconfidence. The mapping into CycloneDX usesevidence.identity.methods[]for identity-bearing attributes andproperties[]with nameaibom.evidence.sourcefor others. See PRD §9.4 and FR1.5. -
D-003: Image digest unresolved state. When no running pod has yet reported an
imageID(workload just created, pods in ImagePullBackOff), the BOM emits the image component withconfidence: unresolvedrather than fabricating a digest or omitting the field. This is an explicit "not yet known" state distinct from "known."
Status: active Introduced in: Phase 6 (BOM builder) Spec section: §5.6 (Evidence), §5.5 (Component.Evidence), §6.3 (Properties) Trusera comparison: similar — Trusera also uses properties extensively, though it does not differentiate evidence-source granularity to the degree we do
What we do
Every Component the builder emits carries three properties identifying its evidence and confidence:
aibom.confidence— one ofdeclared,inferred,unresolvedaibom.evidence.source— one of the closedEvidenceSourceconstants (pod_annotation,env_var,image_reference, etc.)aibom.evidence.locator— a human-readable JSON-path-style pointer to the manifest field the value was extracted from
The CycloneDX Component.Evidence field (a structured
Evidence.Identity.Methods[] block) is NOT populated in v1. Workload-level
aggregate confidence is exposed as aibom.confidence in
metadata.properties[].
What the spec says
CycloneDX 1.6 §5.5 defines Component.Evidence as a structured object
with identity, occurrences, callstack, licenses, and copyright
sub-fields. Evidence.Identity is a list of identification methods, each
with a confidence value from 0.0 to 1.0 and a technique enum
(source-code-analysis, binary-analysis, attestation, etc.).
The spec is silent on AI-specific evidence semantics; attestation is the
closest fit for our claimed-vs-verified signature work (D-001) but does
not encode "this value came from an env var named HF_MODEL_ID" cleanly.
Why we diverge
v1 ships a flat, auditor-readable property-based encoding because:
- Time-to-correct-output. Properties are unambiguously schema-valid
for any name/value pair. The structured
Evidence.Identitymapping requires careful per-attribute decisions abouttechniqueandconfidencemapping that would block v1 schedule on debate. - Auditor accessibility. A flat
aibom.evidence.source = env_varproperty is grep-able in a BOM JSON. A nestedevidence.identity[0].methods[0].confidence = 0.7is harder to read and the float-confidence interpretation is unclear. - Library agnosticism. Property encoding doesn't depend on
cyclonedx-go correctly modeling all of
Evidence. Properties survive any future library swap.
Planned v2 refinement (additive, non-breaking)
v2 will ADD native CycloneDX structured evidence to every Component that carries a property-based one today. Specifically:
- Populate
Component.Evidence.Identity.Methods[]withtechniquemapped fromEvidenceSourceandconfidencemapped from our string tier (declared→ 0.9,inferred→ 0.5). - Map signature claims (D-001) into
technique=attestation. - Keep the existing
aibom.evidence.*andaibom.confidenceproperties for one v2 release so consumers depending on the property-based shape have time to migrate. Dual-emit during the transition. - Document the property-form deprecation in the release notes; remove in v3 if no consumers are still using it.
This migration is intentionally additive: v1 BOMs remain valid v2 BOMs. No customer or auditor breakage at the v2 cut.
Upstream tracking
No upstream issue yet. Open one when v2 implementation begins; the property-naming conventions we're adopting are candidates for the proposed "Kubernetes runtime ML-BOM profile" the project is moving toward (see PRD §9.4).
Example BOM fragment (v1)
{
"type": "machine-learning-model",
"name": "meta-llama/Llama-3.1-8B-Instruct",
"properties": [
{"name": "aibom.confidence", "value": "declared"},
{"name": "aibom.evidence.source", "value": "container_arg"},
{"name": "aibom.evidence.locator", "value": "spec.template.spec.containers[0].args[0 1](--model)"}
]
}Example BOM fragment (v2, additive)
{
"type": "machine-learning-model",
"name": "meta-llama/Llama-3.1-8B-Instruct",
"properties": [
{"name": "aibom.confidence", "value": "declared"},
{"name": "aibom.evidence.source", "value": "container_arg"},
{"name": "aibom.evidence.locator", "value": "spec.template.spec.containers[0].args[0 1](--model)"}
],
"evidence": {
"identity": [{
"field": "name",
"concludedValue": "meta-llama/Llama-3.1-8B-Instruct",
"methods": [{
"technique": "manifest-analysis",
"confidence": 0.9,
"value": "spec.template.spec.containers[0].args[0 1](--model)"
}]
}]
}
}Additional entries will be added as scraper and BOM-builder code lands.