5.9 KiB
Advisory AI Evidence Payloads (LNM-Aligned)
Updated: 2025-11-24 · Owner: Advisory AI Docs Guild · Sprint: 0111 (AIAI-RAG-31-003)
This document defines how Advisory AI consumes Link-Not-Merge (LNM) observations and linksets for Retrieval-Augmented Generation (RAG). It aligns payloads with the frozen LNM v1 schema (docs/modules/concelier/link-not-merge-schema.md, 2025-11-17) and replaces prior draft payloads. CLI/Policy artefacts (CLI-VULN-29-001, CLI-VEX-30-001, policyVersion digests) are referenced but optional at runtime; missing artefacts trigger deterministic 409 advisory.contextUnavailable responses rather than fallback merging. A deterministic SBOM context fixture lives at out/console/guardrails/cli-vuln-29-001/sample-sbom-context.json (SHA256 421af53f9eeba6903098d292fbd56f98be62ea6130b5161859889bf11d699d18) and is used in the examples below.
1) Input envelope (per task)
{
"advisoryKey": "csaf:redhat:RHSA-2025:1001",
"profile": "fips-local",
"policyVersion": "2025.10.1",
"lnm": {
"observationIds": ["6561e41b3e3f4a6e9d3b91c1", "6561e41b3e3f4a6e9d3b91c2"],
"linksetId": "6561e41b3e3f4a6e9d3b91d0",
"provenanceHash": "sha256:0f7c...9ad3"
},
"sbom": {
"artifactId": "registry.stella-ops.internal/runtime/api",
"purl": "pkg:oci/runtime-api@sha256:d2c3...",
"timelineClamp": 500,
"dependencyPathClamp": 200
}
}
Rules:
lnm.linksetIdandlnm.observationIdsare required. Missing values →409 advisory.contextUnavailable.provenanceHashmust match the hash list embedded in the LNM linkset; Advisory AI refuses linksets whose hashes mismatch.- SBOM fields optional; if absent, remediation tasks skip SBOM deltas and still return deterministic outputs.
2) Canonical chunk mapping
| LNM source | Advisory AI chunk | Transformation |
|---|---|---|
advisory_observations._id |
source_id |
Stored verbatim; used for citations. |
advisory_observations.advisoryId |
advisory_key |
Also populates content_hash seed. |
advisory_observations.summary |
text |
Trimmed, Markdown-safe. |
advisory_observations.affected[].purl |
purl |
Lowercased, deduped; no range merging. |
advisory_observations.severities[] |
severity |
Passed through; multiple severities allowed. |
advisory_observations.references[] |
references |
Sorted for determinism. |
advisory_observations.relationships[] |
relationships |
Surface upstream type/source/target/provenance; no merge. |
advisory_observations.provenance.sourceArtifactSha |
content_hash |
Drives dedup + cache key. |
advisory_linksets.conflicts[] |
conflicts |
Serialized verbatim for conflict tasks. |
| `advisory_linksets.normalized.purls | versions | ranges |
Chunk ordering: observations sorted by (source, advisoryId, provenance.fetchedAt) as per LNM invariant; chunks are emitted in the same order to keep cache keys stable. SBOM deltas, when present, append after observations but before conflict echoes to keep hashes reproducible with and without SBOM context.
3) Output citation rules
citations[n].sourceIdpoints to the LNMsource_id;citations[n].urimust remain the upstream reference URI when present.- If SBOM deltas are included, they appear as separate citations with
kind: "sbom"andsourceIdbuilt from SBOM context digest (sbom:{artifactId}:{digest}). - Conflict outputs must echo
linkset.conflicts[].reasonin the Markdown body with matching citation indexes; guardrails block outputs where a conflict reason lacks a citation.
4) Error conditions (aligned to LNM)
| Condition | Code | Notes |
|---|---|---|
Missing lnm.linksetId or lnm.observationIds |
409 advisory.contextUnavailable |
Caller should pass LNM IDs; retry once upstream emits them. |
Hash mismatch between provenanceHash and linkset |
409 advisory.contextHashMismatch |
Indicates tampering or stale payload; retry after refreshing linkset. |
| Observation count exceeds clamp (defaults: 200 obs, 600 chunks) | 413 advisory.contextTooLarge |
Caller may request narrower preferredSections or reduce obs set. |
| Conflicts array empty for conflict task | 422 advisory.conflict.noConflicts |
Signals upstream data gap; reported to Concelier. |
5) Sample normalized RAG bundle
{
"taskType": "Summary",
"advisoryKey": "csaf:redhat:RHSA-2025:1001",
"lnmBundle": {
"linksetId": "6561e41b3e3f4a6e9d3b91d0",
"provenanceHash": "sha256:0f7c...9ad3",
"chunks": [
{
"source_id": "concelier:ghsa:GHSA-xxxx:obs:6561e41b3e3f4a6e9d3b91c1",
"content_hash": "sha256:1234...",
"advisory_key": "csaf:redhat:RHSA-2025:1001",
"purl": "pkg:maven/org.example/foo@1.2.3",
"severity": [{"system":"cvssv3","score":7.8,"vector":"AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"}],
"references": ["https://access.redhat.com/errata/RHSA-2025:1001"],
"relationships": [{"type":"affects","source":"nvd","target":"cpe:/o:redhat:enterprise_linux:9"}]
}
],
"conflicts": [
{"field":"affected.versions","reason":"vendor_range_differs","values":["<1.2.0","<=1.2.3"]}
]
},
"sbomSummary": {
"artifactId": "registry.stella-ops.internal/runtime/api",
"versionTimeline": 8,
"dependencyPaths": 5
}
}
Operators can store this bundle alongside plan cache entries; the lnmBundle.provenanceHash proves the evidence set matches the frozen Concelier linkset.
6) Operator validation steps
- Verify LNM collections at schema v1 (2025-11-17 freeze) before enabling Advisory AI tasks.
- Ensure
lnm.provenanceHashmatches linksetobservationHashesbefore calling Advisory AI. - Keep clamps deterministic: observations ≤200, chunks ≤600, timeline entries ≤500, dependency paths ≤200 (defaults; override only if documented).
- When running offline, include LNM linkset exports in the Offline Kit to preserve citation replay.