Files
git.stella-ops.org/docs/api/signals/reachability-contract.md
StellaOps Bot 999e26a48e up
2025-12-13 02:22:15 +02:00

64 lines
3.3 KiB
Markdown

# Signals API (Reachability)
**Status:** Working contract (aligns with `src/Signals/StellaOps.Signals/Program.cs`).
## Auth, scopes, sealed mode
- **Scopes:** `signals:read`, `signals:write`, `signals:admin` (endpoint-specific; see below).
- **Dev fallback:** when Authority auth is disabled, requests must include `X-Scopes: <space-separated scopes>` (example: `X-Scopes: signals:write`).
- **Sealed mode:** when enabled, Signals may return `503` with `{ "error": "sealed-mode evidence invalid", ... }`.
## Endpoints
### Health & status
- `GET /healthz` (anonymous)
- `GET /readyz` (anonymous; `503` when not ready or sealed-mode blocked)
- `GET /signals/ping` (scope: `signals:read`, response: `204`)
- `GET /signals/status` (scope: `signals:read`)
### Callgraph ingestion & retrieval
- `POST /signals/callgraphs` (scope: `signals:write`)
- Body: `CallgraphIngestRequest` (`language`, `component`, `version`, `artifactContentBase64`, …).
- Response: `202 Accepted` with `CallgraphIngestResponse` and `Location: /signals/callgraphs/{callgraphId}`.
- Graph hash is computed deterministically from normalized nodes/edges/roots; see `graphHash` in the response.
- `GET /signals/callgraphs/{callgraphId}` (scope: `signals:read`)
- `GET /signals/callgraphs/{callgraphId}/manifest` (scope: `signals:read`)
Sample request: `docs/api/signals/samples/callgraph-sample.json`
### Runtime facts ingestion
- `POST /signals/runtime-facts` (scope: `signals:write`)
- Body: `RuntimeFactsIngestRequest` with `subject`, `callgraphId`, and `events[]`.
- `POST /signals/runtime-facts/ndjson?callgraphId=...&scanId=...` (scope: `signals:write`)
- Body: NDJSON of `RuntimeFactEvent` objects; `Content-Encoding: gzip` supported.
- `POST /signals/runtime-facts/synthetic` (scope: `signals:write`)
- Generates a small deterministic sample set of runtime events for a callgraph to unblock testing.
### Unknowns ingestion & retrieval
- `POST /signals/unknowns` (scope: `signals:write`)
- Body: `UnknownsIngestRequest` (`subject`, `callgraphId`, `unknowns[]`).
- `GET /signals/unknowns/{subjectKey}` (scope: `signals:read`)
### Reachability scoring & facts
- `POST /signals/reachability/recompute` (scope: `signals:admin`)
- Body: `ReachabilityRecomputeRequest` (`callgraphId`, `subject`, `entryPoints[]`, `targets[]`, optional `runtimeHits[]`, optional `blockedEdges[]`).
- Response: `200 OK` with `{ id, callgraphId, subject, entryPoints, states, computedAt }`.
- `GET /signals/facts/{subjectKey}` (scope: `signals:read`)
- Response: `ReachabilityFactDocument` (per-target states, `score`, `riskScore`, unknowns pressure, optional uncertainty states, runtime facts snapshot).
Sample fact: `docs/api/signals/samples/facts-sample.json`
### Reachability union bundle ingestion (CAS layout)
- `POST /signals/reachability/union` (scope: `signals:write`)
- Body: `application/zip` bundle containing `nodes.ndjson`, `edges.ndjson`, `meta.json`.
- Optional header: `X-Analysis-Id` (defaults to a new GUID if omitted).
- Response: `202 Accepted` with `ReachabilityUnionIngestResponse` and `Location: /signals/reachability/union/{analysisId}/meta`.
- `GET /signals/reachability/union/{analysisId}/meta` (scope: `signals:read`)
- `GET /signals/reachability/union/{analysisId}/files/{fileName}` (scope: `signals:read`)