# Concelier · Policy Engine Linkset API Prep - **Date:** 2025-11-20 - **Scope:** PREP-CONCELIER-POLICY-20-001 (LNM APIs not exposed via OpenAPI) - **Working directory:** `src/Concelier/StellaOps.Concelier.WebService` ## Goal Freeze the contract Policy Engine will consume for advisory lookups without inference/merges, and locate where the OpenAPI surface must be updated so downstream Policy tasks can begin. ## API surface to expose - **Endpoint:** `GET /v1/lnm/linksets` - **Query params:** - `purl` (repeatable), `cpe`, `ghsa`, `cve`, `advisoryId`, `source` (nvd|ghsa|osv|vendor:), `severityMin`, `severityMax`, `publishedSince`, `modifiedSince`, `tenant` (header enforced, not query), `page` (default 1), `pageSize` (default 50, max 200), `sort` (publishedAt|modifiedAt|severity desc|source|advisoryId; default modifiedAt desc). - **Response:** deterministic ordering; body fields = `advisoryId`, `source`, `purl[]`, `cpe[]`, `summary`, `publishedAt`, `modifiedAt`, `severity` (source-native), `status` (facts only), `provenance` (`ingestedAt`, `connectorId`, `evidenceHash`, `dsseEnvelopeHash?`), `conflicts[]` (raw disagreements, no merged verdicts), `timeline[]` (raw timestamps + hashes), `remarks[]` (human notes, optional). - **Endpoint:** `GET /v1/lnm/linksets/{advisoryId}` - Mirrors above fields; adds `normalized` block for any canonicalized IDs; `cached` flag already added in Sprint 110.B endpoint work. - **Endpoint:** `POST /v1/lnm/linksets/search` - Accepts body with same filters as query params plus boolean `includeTimeline`, `includeObservations` (default false). Must respect tenant guard and AOC (no inferred verdicts or merges). ## OpenAPI tasks - Source file location: `src/Concelier/StellaOps.Concelier.WebService/openapi/concelier-lnm.yaml` (to be created / updated alongside code) and published copy under `docs/api/concelier/`. - Add components: - `LinksetProvenance` object (ingestedAt, connectorId, evidenceHash, dsseEnvelopeHash?). - `LinksetConflict` object (source, field, observedValue, observedAt, evidenceHash). - `LinksetTimeline` object (event, at, evidenceHash, dsseEnvelopeHash?). - Pagination envelope: `{ "items": [...], "page": 1, "pageSize": 50, "total": }` with stable ordering guarantees quoted above. - Security: `Tenant` header required; bearer/mtls unchanged from existing WebService. ## Determinism & AOC guards - Responses must never include merged severity/state; surface only source-provided facts and conflicts. - Sorting: primary `modifiedAt desc`, tie-breaker `advisoryId asc`, then `source asc` for deterministic pagination. - Cache: the `/linksets/{advisoryId}` endpoint may serve cached entries but must include `cached: true|false` and `provenance.evidenceHash` so Policy Engine can verify integrity. ## Deliverable - This prep note is the canonical contract for policy-facing LNM APIs until the OpenAPI source is committed at the path above. - Downstream tasks (POLICY-ENGINE-20-001 and linked Policy Engine sprints) should bind to these fields; any deviations must update this prep note and the sprint’s Decisions & Risks.