# Canonical Record Definitions

> Source of truth for the normalized advisory schema emitted by `StellaOps.Feedser.Models`.
> Keep this document in sync with the public record types under `StellaOps.Feedser.Models` and
> update it whenever a new field is introduced or semantics change.

## Advisory

| Field | Type | Required | Notes |
|-------|------|----------|-------|
| `advisoryKey` | string | yes | Globally unique identifier selected by the merge layer (often a CVE/GHSA/vendor key). Stored lowercased unless vendor casing is significant. |
| `title` | string | yes | Human readable title. Must be non-empty and trimmed. |
| `summary` | string? | optional | Short description; trimmed to `null` when empty. |
| `language` | string? | optional | ISO language code (lowercase). |
| `published` | DateTimeOffset? | optional | UTC timestamp when vendor originally published. |
| `modified` | DateTimeOffset? | optional | UTC timestamp when vendor last updated. |
| `severity` | string? | optional | Normalized severity label (`critical`, `high`, etc.). |
| `exploitKnown` | bool | yes | Whether KEV/other sources confirm active exploitation. |
| `aliases` | string[] | yes | Sorted, de-duplicated list of normalized aliases (see [Alias Schemes](#alias-schemes)). |
| `credits` | AdvisoryCredit[] | yes | Deterministically ordered acknowledgements (role + contact metadata). |
| `references` | AdvisoryReference[] | yes | Deterministically ordered reference set. |
| `affectedPackages` | AffectedPackage[] | yes | Deterministically ordered affected packages. |
| `cvssMetrics` | CvssMetric[] | yes | Deterministically ordered CVSS metrics (v3, v4 first). |
| `provenance` | AdvisoryProvenance[] | yes | Normalized provenance entries sorted by source then kind then recorded timestamp. |

### Invariants
- Collections are immutable (`ImmutableArray<T>`) and always sorted deterministically.
- `AdvisoryKey` and `Title` are mandatory and trimmed.
- All timestamps are stored as UTC.
- Aliases and references leverage helper registries for validation.

## AdvisoryReference

| Field | Type | Required | Notes |
|-------|------|----------|-------|
| `url` | string | yes | Absolute HTTP/HTTPS URL. |
| `kind` | string? | optional | Categorized reference role (e.g. `advisory`, `patch`, `changelog`). |
| `sourceTag` | string? | optional | Free-form tag identifying originating source. |
| `summary` | string? | optional | Short description. |
| `provenance` | AdvisoryProvenance | yes | Provenance entry describing how the reference was mapped. |

Deterministic ordering: by `url`, then `kind`, then `sourceTag`, then `provenance.RecordedAt`.

## AdvisoryCredit

| Field | Type | Required | Notes |
|-------|------|----------|-------|
| `displayName` | string | yes | Human-readable acknowledgement (reporter, maintainer, analyst, etc.). |
| `role` | string? | optional | Normalized role token (lowercase with `_` separators). |
| `contacts` | string[] | yes | Sorted set of vendor-supplied handles or URLs; may be empty. |
| `provenance` | AdvisoryProvenance | yes | Provenance entry describing how the credit was captured. |

Deterministic ordering: by `role` (nulls first) then `displayName`.

## AffectedPackage

| Field | Type | Required | Notes |
|-------|------|----------|-------|
| `type` | string | yes | Semantic type (`semver`, `rpm`, `deb`, `purl`, `cpe`, etc.). Lowercase. |
| `identifier` | string | yes | Canonical identifier (package name, PURL, CPE, NEVRA, etc.). |
| `platform` | string? | optional | Explicit platform / distro (e.g. `ubuntu`, `rhel-8`). |
| `versionRanges` | AffectedVersionRange[] | yes | Deduplicated + sorted by introduced/fixed/last/expr/kind. |
| `statuses` | AffectedPackageStatus[] | yes | Optional status flags (e.g. `fixed`, `affected`). |
| `provenance` | AdvisoryProvenance[] | yes | Provenance entries for package level metadata. |

Deterministic ordering: packages sorted by `type`, then `identifier`, then `platform` (ordinal).

## AffectedVersionRange

| Field | Type | Required | Notes |
|-------|------|----------|-------|
| `rangeKind` | string | yes | Classification of range semantics (`semver`, `evr`, `nevra`, `version`, `purl`). Lowercase. |
| `introducedVersion` | string? | optional | Inclusive lower bound when impact begins. |
| `fixedVersion` | string? | optional | Exclusive bounding version containing the fix. |
| `lastAffectedVersion` | string? | optional | Inclusive upper bound when no fix exists. |
| `rangeExpression` | string? | optional | Normalized textual expression for non-simple ranges. |
| `provenance` | AdvisoryProvenance | yes | Provenance entry for the range. |
| `primitives` | RangePrimitives? | optional | Structured metadata (SemVer/Nevra/Evr/vendor extensions) when available. |

Comparers/equality ignore provenance differences.

## CvssMetric

| Field | Type | Required | Notes |
|-------|------|----------|-------|
| `version` | string | yes | `2.0`, `3.0`, `3.1`, `4.0`, etc. |
| `vector` | string | yes | Official CVSS vector string. |
| `score` | double | yes | CVSS base score (0.0-10.0). |
| `severity` | string | yes | Severity label mapped from score or vendor metadata. |
| `provenance` | AdvisoryProvenance | yes | Provenance entry. |

Sorted by version then vector for determinism.

## AdvisoryProvenance

| Field | Type | Required | Notes |
|-------|------|----------|-------|
| `source` | string | yes | Logical source identifier (`nvd`, `redhat`, `osv`, etc.). |
| `kind` | string | yes | Operation performed (`fetch`, `parse`, `map`, `merge`, `enrich`). |
| `value` | string? | optional | Free-form pipeline detail (parser identifier, rule set, resume cursor). |
| `recordedAt` | DateTimeOffset | yes | UTC timestamp when provenance was captured. |
| `fieldMask` | string[] | optional | Canonical field coverage expressed as lowercase masks (e.g. `affectedpackages[]`, `affectedpackages[].versionranges[]`). |

### Provenance Mask Expectations
Each canonical field is expected to carry at least one provenance entry derived from the
responsible pipeline stage. Populate `fieldMask` with the lowercase canonical mask(s) describing the
covered field(s); downstream metrics and resume helpers rely on this signal to reason about
coverage. When aggregating provenance from subcomponents (e.g., affected package ranges), merge code
should ensure:

- Advisory level provenance documents the source document and merge actions.
- References, packages, ranges, and metrics each include their own provenance entry reflecting
  the most specific source (vendor feed, computed normalization, etc.).
- Export-specific metadata (digest manifests, offline bundles) include exporter version alongside
  the builder metadata.

## Alias Schemes

Supported alias scheme prefixes:

- `CVE-`
- `GHSA-`
- `OSV-`
- `JVN-`, `JVNDB-`
- `BDU-`
- `VU#`
- `MSRC-`
- `CISCO-SA-`
- `ORACLE-CPU`
- `APSB-`, `APA-`
- `APPLE-HT`
- `CHROMIUM:` / `CHROMIUM-`
- `VMSA-`
- `RHSA-`
- `USN-`
- `DSA-`
- `SUSE-SU-`
- `ICSA-`
- `CWE-`
- `cpe:`
- `pkg:` (Package URL / PURL)

The registry exposed via `AliasSchemes` and `AliasSchemeRegistry` can be used to validate aliases and
drive downstream conditionals without re-implementing pattern rules.
