Concelier Conflict Resolution Runbook

Audience: Stella Ops operators triaging advisory merge conflicts in Concelier.

This runbook explains how to detect, triage, and resolve advisory conflicts surfaced by the Concelier merge engine (AdvisoryPrecedenceMerger, merge-event hashing, and the telemetry counters described below). It builds on the canonical precedence rules and the metrics/logging instrumentation that ships with the merge engine.


1. Precedence Model (recap)


2. Telemetry

InstrumentTypeKey TagsPurpose
concelier.merge.operationsCounterinputsTotal precedence merges executed.
concelier.merge.overridesCounterprimary_source, suppressed_source, primary_rank, suppressed_rankField-level overrides chosen by precedence.
concelier.merge.range_overridesCounteradvisory_key, package_type, primary_source, suppressed_source, primary_range_count, suppressed_range_countPackage range overrides emitted by AffectedPackagePrecedenceResolver.
concelier.merge.conflictsCountertype (severity, precedence_tie), reason (mismatch, primary_missing, equal_rank)Conflicts requiring operator review.
concelier.merge.identity_conflictsCounterscheme, alias_value, advisory_countAlias collisions surfaced by the identity graph.

Structured logs

Expect all logs at Information. Ensure OTEL exporters include the scope StellaOps.Concelier.Merge.


3. Detection & Alerting

  1. Dashboard panels
    • concelier.merge.conflicts - table grouped by type/reason. Alert when > 0 in a 15 minute window.
    • concelier.merge.range_overrides - stacked bar by package_type. Spikes highlight vendor PSIRT overrides over registry data.
    • concelier.merge.overrides with primary_source|suppressed_source - catches unexpected precedence flips (e.g., OSV overtaking GHSA).
    • concelier.merge.identity_conflicts - single-stat; alert when alias collisions occur more than once per day.
  2. Log based alerts
    • eventId=1002 with reason="equal_rank" - indicates precedence table gaps; page merge owners.
    • eventId=1002 with reason="mismatch" - severity disagreement; open connector bug if sustained.
  3. Job health
    • stella db merge exit code 1 signifies unresolved conflicts. Pipe to automation that captures logs and notifies #concelier-ops.

Threshold updates (2025-10-12)


4. Triage Workflow

  1. Confirm job context
    • stella db merge (CLI) or POST /jobs/merge:reconcile (API) to rehydrate the merge job. Use --verbose to stream structured logs during triage.
  2. Inspect metrics
    • Correlate spikes in concelier.merge.conflicts with primary_source/suppressed_source tags from concelier.merge.overrides.
  3. Pull structured logs
    • Example (vector output):
      jq 'select(.EventId.Name=="PrecedenceConflict") | {advisory: .State[0].Value, type: .ConflictType, reason: .Reason, primary: .PrimarySources, suppressed: .SuppressedSources}' stellaops-concelier.log
      
  4. Review merge events
    • mongosh:
      use concelier;
      db.merge_event.find({ advisoryKey: "CVE-2025-1234" }).sort({ mergedAt: -1 }).limit(5);
      
    • Compare beforeHash vs afterHash to confirm the merge actually changed canonical output.
  5. Interrogate provenance
    • db.advisories.findOne({ advisoryKey: "CVE-2025-1234" }, { title: 1, severity: 1, provenance: 1, "affectedPackages.provenance": 1 })
    • Check provenance[].decisionReason values (precedence, freshness, tie-breaker) to understand why the winning field was chosen.

5. Conflict Classification Matrix

5.1 Linkset Conflicts (v2 Correlation)

Linkset conflicts now carry typed severities that affect confidence scoring:

SeverityPenaltyConflictsTriage Priority
Hard-0.30 to -0.40distinct-cves, disjoint-version-rangesHigh - investigate immediately
Soft-0.05 to -0.10affected-range-divergence, severity-mismatch, alias-inconsistencyMedium - review in batch
Info0.00metadata-gap, reference-clash (disjoint only)Low - informational
Conflict ReasonSeverityLikely CauseImmediate Action
distinct-cvesHardTwo different CVE-* IDs in same linkset clusterInvestigate alias mappings; likely compound advisory or incorrect aliasing
disjoint-version-rangesHardSame package, no version overlap between sourcesCheck if distro backport; verify connector range parsing
affected-range-divergenceSoftRanges overlap but differOften benign (distro vs upstream versioning); monitor trends
severity-mismatchSoftCVSS scores differ by > 1.0Normal for cross-source; freshest source typically wins
alias-inconsistencySoftDisconnected alias graph (no shared CVE)Review alias extraction; may indicate unrelated advisories grouped

5.2 Merge Conflicts (Legacy)

SignalLikely CauseImmediate Action
reason="mismatch" with type="severity"Upstream feeds disagree on CVSS vector/severity.Verify which feed is freshest; if correctness is known, adjust connector mapping or precedence override.
reason="primary_missing"Higher-ranked source lacks the field entirely.Backfill connector data or temporarily allow lower-ranked source via precedence override.
reason="equal_rank"Two feeds share the same precedence rank (custom config or missing entry).Update concelier:merge:precedence:ranks to break the tie; restart merge job.
Rising concelier.merge.range_overrides for a package typeVendor PSIRT now supplies richer ranges.Validate connectors emit decisionReason="precedence" and update dashboards to treat registry ranges as fallback.
concelier.merge.identity_conflicts > 0Alias scheme mapping produced collisions (duplicate CVE <-> advisory pairs).Inspect Alias collision log payload; reconcile the alias graph by adjusting connector alias output.

6. Resolution Playbook

  1. Connector data fix
    • Re-run the offending connector stages (stella db fetch --source ghsa --stage map etc.).
    • Once fixed, rerun merge and verify decisionReason reflects freshness or precedence as expected.
  2. Temporary precedence override
    • Edit etc/concelier.yaml:
      concelier:
        merge:
          precedence:
            ranks:
              osv: 1
              ghsa: 0
      
    • Restart Concelier workers; confirm tags in concelier.merge.overrides show the new ranks.
    • Document the override with expiry in the change log.
  3. Alias remediation
    • Update connector mapping rules to weed out duplicate aliases (e.g., skip GHSA aliases that mirror CVE IDs).
    • Flush cached alias graphs if necessary (db.alias_graph.drop() is destructive-coordinate with Storage before issuing).
  4. Escalation
    • If override metrics spike due to upstream regression, open an incident with Security Guild, referencing merge logs and merge_event IDs.

7. Validation Checklist


8. Reference Material

Keep this runbook synchronized with the merge engine and update alert thresholds as baseline volumes change.


9. Synthetic Regression Fixtures

dotnet test src/Concelier/StellaOps.Concelier.PluginBinaries/StellaOps.Concelier.Connector.Ghsa.Tests/StellaOps.Concelier.Connector.Ghsa.Tests.csproj --filter GhsaConflictFixtureTests
dotnet test src/Concelier/StellaOps.Concelier.PluginBinaries/StellaOps.Concelier.Connector.Nvd.Tests/StellaOps.Concelier.Connector.Nvd.Tests.csproj --filter NvdConflictFixtureTests
dotnet test src/Concelier/StellaOps.Concelier.PluginBinaries/StellaOps.Concelier.Connector.Osv.Tests/StellaOps.Concelier.Connector.Osv.Tests.csproj --filter OsvConflictFixtureTests
dotnet test src/Concelier/__Tests/StellaOps.Concelier.Merge.Tests/StellaOps.Concelier.Merge.Tests.csproj --filter MergeAsync_AppliesCanonicalRulesAndPersistsDecisions

10. Change Log

Date (UTC)ChangeNotes
2025-10-16Ops review signed off after connector expansion (CCCS, CERT-Bund, KISA, ICS CISA, MSRC) landed. Alert thresholds from §3 reaffirmed; dashboards updated to watch attachment signals emitted by ICS CISA connector.Ops sign-off recorded by Concelier Ops Guild; no additional overrides required.