105 lines
5.3 KiB
Markdown
105 lines
5.3 KiB
Markdown
# 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.
|