# Advisory AI Evidence Payloads (LNM-Aligned) _Updated: 2025-11-18 · 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. ## 1) Input envelope (per task) ```json { "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.linksetId` and `lnm.observationIds` are **required**. Missing values → `409 advisory.contextUnavailable`. - `provenanceHash` must 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|severities` | `normalized` | Used as hints only; never overwrite observation fields. | 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. ## 3) Output citation rules - `citations[n].sourceId` points to the LNM `source_id`; `citations[n].uri` must remain the upstream reference URI when present. - If SBOM deltas are included, they appear as separate citations with `kind: "sbom"` and `sourceId` built from SBOM context digest (`sbom:{artifactId}:{digest}`). - Conflict outputs must echo `linkset.conflicts[].reason` in 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 ```json { "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.provenanceHash` matches linkset `observationHashes` before 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.