# Linkset Conflicts API Reference (v1) Status: stable; aligns with LNM v1 (frozen 2025-11-17). ## Intent - Document conflict detection and representation in the Link-Not-Merge system. - Conflicts are surfaced but never automatically resolved; consumers implement their own resolution strategy. - This reference describes conflict types, detection logic, and how conflicts appear in API responses. ## Philosophy: Link-Not-Merge The Concelier LNM (Link-Not-Merge) approach differs from traditional advisory aggregation: - **Link**: Observations from multiple sources are linked together via shared identifiers (CVE, GHSA, PURL, CPE). - **Not Merge**: Conflicting data is preserved with full provenance rather than collapsed into a single "truth". - **Surface, Don't Resolve**: Conflicts are clearly marked for downstream consumers to handle according to their own policies. ## Conflict Types ### severity-mismatch Sources disagree on severity rating. ```json { "field": "severity", "reason": "severity-mismatch", "observedValue": "critical", "observedAt": "2025-11-18T08:00:00Z", "evidenceHash": "sha256:f6e5d4c3b2a1098765432109876543210fedcba0987654321fedcba098765432" } ``` **Detection**: Triggered when severity labels (critical, high, medium, low) or CVSS scores differ by more than 1.0 points between observations. **Common causes**: - Different CVSS versions (v2 vs v3 vs v3.1) - Vendor-specific severity assessments - Time lag between source updates ### version-range-conflict Sources disagree on affected version ranges. ```json { "field": "affected.ranges", "reason": "version-range-conflict", "observedValue": "{\"fixed\": \"2.0.0\"}", "observedAt": "2025-11-19T12:00:00Z", "evidenceHash": "sha256:a1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456" } ``` **Detection**: Triggered when version range events differ between observations for the same package. **Common causes**: - Backports creating different fix points per distribution - Vendor patches not reflected in upstream - Different ecosystem-specific versioning ### status-conflict Sources disagree on vulnerability status. ```json { "field": "status", "reason": "status-conflict", "observedValue": "not_affected", "observedAt": "2025-11-20T09:00:00Z", "evidenceHash": "sha256:b2c3d4e5f6a789012345678901234567890abcdef1234567890abcdef1234567b" } ``` **Detection**: Triggered when status values (affected, not_affected, under_investigation, fixed) differ. **Common causes**: - VEX statements from vendors - Incomplete upstream analysis - Context-specific applicability (e.g., platform-dependent) ### cpe-mismatch Sources disagree on CPE identifiers. ```json { "field": "cpe", "reason": "cpe-mismatch", "observedValue": "cpe:2.3:a:example:lib:*:*:*:*:*:*:*:*", "observedAt": "2025-11-18T16:00:00Z", "evidenceHash": "sha256:c3d4e5f6a789012345678901234567890abcdef1234567890abcdef123456789c" } ``` **Detection**: Triggered when CPE identifiers for the same advisory don't match. **Common causes**: - Different CPE dictionary versions - Vendor vs product naming variations - Platform-specific CPE assignments ### reference-conflict Sources provide conflicting reference information. ```json { "field": "references", "reason": "reference-conflict", "observedValue": "https://example.com/advisory/different", "observedAt": "2025-11-21T10:00:00Z", "evidenceHash": "sha256:d4e5f6a789012345678901234567890abcdef1234567890abcdef123456789def" } ``` ## Conflict in Linkset Response Full linkset with multiple conflicts: ```json { "advisoryId": "CVE-2024-9999", "source": "aggregated", "purl": ["pkg:maven/org.example/library@1.5.0"], "cpe": [ "cpe:2.3:a:example:library:1.5.0:*:*:*:*:*:*:*", "cpe:2.3:a:example_inc:lib:1.5.0:*:*:*:*:java:*:*" ], "summary": "Deserialization vulnerability in example library", "publishedAt": "2024-09-01T00:00:00Z", "modifiedAt": "2024-09-15T00:00:00Z", "severity": "high", "status": "affected", "provenance": { "ingestedAt": "2025-11-20T10:30:00Z", "connectorId": "multi-source-aggregator", "evidenceHash": "sha256:aggregated-evidence-hash" }, "conflicts": [ { "field": "severity", "reason": "severity-mismatch", "observedValue": "critical", "observedAt": "2025-11-15T10:00:00Z", "evidenceHash": "sha256:nvd-observation-hash" }, { "field": "severity", "reason": "severity-mismatch", "observedValue": "medium", "observedAt": "2025-11-18T14:00:00Z", "evidenceHash": "sha256:vendor-observation-hash" }, { "field": "cpe", "reason": "cpe-mismatch", "observedValue": "cpe:2.3:a:example_inc:lib:1.5.0:*:*:*:*:java:*:*", "observedAt": "2025-11-17T08:00:00Z", "evidenceHash": "sha256:github-observation-hash" }, { "field": "affected.ranges", "reason": "version-range-conflict", "observedValue": "{\"type\": \"SEMVER\", \"events\": [{\"introduced\": \"1.0.0\"}, {\"fixed\": \"1.5.1\"}]}", "observedAt": "2025-11-19T12:00:00Z", "evidenceHash": "sha256:distro-observation-hash" } ], "timeline": [ {"event": "first-observed", "at": "2025-11-15T10:00:00Z", "evidenceHash": "sha256:nvd-observation-hash"}, {"event": "conflict-detected", "at": "2025-11-17T08:00:00Z", "evidenceHash": "sha256:github-observation-hash"}, {"event": "conflict-detected", "at": "2025-11-18T14:00:00Z", "evidenceHash": "sha256:vendor-observation-hash"}, {"event": "conflict-detected", "at": "2025-11-19T12:00:00Z", "evidenceHash": "sha256:distro-observation-hash"} ], "normalized": { "aliases": ["CVE-2024-9999", "GHSA-xxxx-yyyy-zzzz"], "severities": [ {"source": "nvd", "type": "CVSS_V3", "score": 9.8, "label": "critical"}, {"source": "github", "type": "CVSS_V3", "score": 7.5, "label": "high"}, {"source": "vendor", "type": "CVSS_V3", "score": 5.3, "label": "medium"} ], "ranges": [ {"source": "nvd", "type": "SEMVER", "introduced": "0", "fixed": "1.6.0"}, {"source": "distro", "type": "SEMVER", "introduced": "1.0.0", "fixed": "1.5.1"} ] }, "cached": false, "observations": [ "obs:nvd:CVE-2024-9999:2025-11-15", "obs:github:GHSA-xxxx-yyyy-zzzz:2025-11-17", "obs:vendor:CVE-2024-9999:2025-11-18", "obs:distro:CVE-2024-9999:2025-11-19" ] } ``` ## Querying for Conflicts ### List Only Linksets with Conflicts ```bash GET /v1/lnm/linksets?includeConflicts=true&hasConflicts=true X-Stella-Tenant: acme ``` ### Filter by Conflict Type ```bash POST /v1/lnm/linksets/search X-Stella-Tenant: acme Content-Type: application/json { "conflictTypes": ["severity-mismatch", "version-range-conflict"], "includeConflicts": true, "pageSize": 50 } ``` ### Advisory Summary with Conflicts ```bash GET /advisories/summary?conflicts_only=true X-Stella-Tenant: acme ``` Response: ```json { "meta": { "tenant": "acme", "count": 3, "sort": "advisory" }, "items": [ { "advisoryKey": "CVE-2024-9999", "aliases": ["CVE-2024-9999", "GHSA-xxxx-yyyy-zzzz"], "source": "aggregated", "confidence": 0.65, "conflicts": [ {"field": "severity", "reason": "severity-mismatch", "sourceIds": ["nvd", "vendor", "github"]} ], "counts": { "observations": 4, "conflictFields": 2 } } ] } ``` ## Conflict Resolution Strategies Concelier does not resolve conflicts, but here are common strategies consumers implement: ### Source Priority Prioritize sources by trust level: ``` nvd > vendor > github > community ``` ### Most Recent Use the most recently observed value: ``` Sort by observedAt desc, take first ``` ### Most Conservative For severity, use the highest rating: ``` critical > high > medium > low ``` ### Voting/Consensus Use the value with most agreement: ``` Count occurrences, take majority ``` ## Conflict Confidence Impact The `confidence` field in linksets reflects conflict presence: - **No conflicts**: confidence ≥ 0.9 - **Minor conflicts** (1-2 fields): confidence 0.7-0.9 - **Major conflicts** (3+ fields or severity): confidence < 0.7 ## Notes - Conflicts are preserved indefinitely; they are only removed if all observations align. - Evidence hashes allow consumers to trace conflicts back to specific observations. - The `timeline` array shows when conflicts were first detected. - Multiple conflicts on the same field from different sources create multiple entries. ## Changelog - 2025-12-06: Initial conflict reference documentation (CONCELIER-WEB-OAS-62-001). - 2025-11-17: LNM v1 conflict model frozen.