Files
git.stella-ops.org/docs/advisory-ai/evidence-payloads.md
master 10212d67c0
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
api-governance / spectral-lint (push) Has been cancelled
Refactor code structure for improved readability and maintainability; removed redundant code blocks and optimized function calls.
2025-11-20 07:50:52 +02:00

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.