# System graph & map

The service-level system graph repowise folds cross-repo signals into, the System Map that renders it, and diagnostics explaining why a contract link formed.

The contracts, package dependencies, and co-changes repowise extracts
([Cross-repo intelligence](https://docs.repowise.dev/multi-repo/cross-repo)) are each a flat list. The workspace layer folds them into a single
normalized **system graph**, the one structure every cross-repo view
reads. It is rebuilt automatically on every
[`repowise update --workspace`](https://docs.repowise.dev/multi-repo/workspace-setup)
and persisted to `.repowise-workspace/system_graph.json`.

## Nodes are services, not repos

A monorepo with three detected service boundaries (a `package.json`,
`go.mod`, or `Cargo.toml` sub-directory) shows three nodes. The repo is
a grouping attribute on each node. A repo with no sub-boundary collapses
to a single repo-root node. Each node carries its provider/consumer
counts, the contract types it participates in, and flags for orphan or
isolated services.

## Edges are typed and honest

Every edge carries:

- a `kind`, one of `http`, `grpc`, `event`, `package`, `co_change`, or `db`;
- a `family`: `runtime`, `data`, `build` or `history`;
- a `strategy`, the rule that made its strongest link (see
  [How each contract and link is made](https://docs.repowise.dev/multi-repo/cross-repo#how-each-contract-and-link-is-made));
- a `match_type`, one of `exact`, `candidate`, `manual`, or `inferred`;
- a `confidence` and a `weight` (how many underlying contracts, deps, or
  co-changes it aggregates);
- `contract_refs` back-pointers, so any view can drill from an edge to
  its evidence.

Edge direction is uniform: **`source` depends on or calls `target`.** A
consumer points to the provider it calls; a dependent repo points to the
repo it imports. Structural edges (contracts, package deps) are flagged
distinctly from behavioral co-change edges, so repowise never conflates
"these change together" with "these call each other".

Fetch the graph over REST with `GET /api/workspace/system-graph`, or
explore it visually in the System Map. `?view=map` returns a lean copy
(no diagnostics, edges carry `ref_count` instead of evidence refs).
`GET /api/workspace/system-graph/links?a=<service>&b=<service>` lists every
contract, service link, package dependency and co-change between two
services, in both directions, with totals per kind, kind and text filters,
paging, and each end's contract origin.

### Evidence state

A graph with no cross-service edges would score as perfectly decoupled, so
every view states how much evidence the graph rests on:

| State | Meaning |
|---|---|
| `measured` | Every service takes part in a runtime dependency |
| `partial` | Edges exist, but part of the estate is out of sight (build references only, services with no detected dependency, repos that yielded no contracts). Figures carry the reasons |
| `insufficient` | Fewer than two services carry a contract, or no structural edge joins two. Scores, cycle verdicts and impact sets read "too little evidence", not clean |

The state and its reason codes appear in `workspace metrics`, `workspace
check`, blast radius, `get_risk` and `get_change_risk` (when short of
measured), and the System Map.

### Service groups

Past 40 services, each service joins at most one group, in this order: a
repo tag `group:<name>` in `.repowise-workspace.yaml` (other tags never make
a group), a shared repo-alias prefix over two or more repos and under half
the estate, then community detection over runtime and data edges. Groups
exist only when two or more form. Each node carries an optional `group`,
and the graph a `groups` summary.

## System Map

The web UI renders the system graph as an always-current diagram on the
System Map tab of a workspace's dashboard (`/w/<workspace-id>/system-map`).
It is the visual counterpart to the REST endpoint, the same nodes and
edges laid out and explorable, never a hand-drawn picture. This is a
different view from the per-repo [Knowledge Graph](https://docs.repowise.dev/dashboard#knowledge-graph)
at `/repos/<id>/knowledge-graph`, which renders one repo's
community-detected module layout instead of the cross-repo service
graph. For one repo's C4 views and Structurizr export, see
[Architecture diagrams](https://docs.repowise.dev/intelligence/architecture-diagrams).

- **Service nodes**, coloured by category (service, frontend, worker,
  library, external), with a health ring rolled up from the owning repo
  and small flags for orphan or isolated services.
- **Typed edges** distinguished by `kind` (colour and glyph) and by
  `match_type` (solid for exact/manual, dashed for candidate, dotted for
  inferred co-change). Behavioral co-change edges read differently from
  structural contract and dependency edges.
- **Levels**: on a grouped estate the map opens on group cards joined by
  bands (link count and kind mix per ordered pair); open a group to see its
  services, and a tray holds services with no runtime or data link. Without
  groups the map is one flat estate. Runtime and data links draw by default;
  build and history are opt-in. The map draws at most 120 nodes and 300
  edges and folds the rest into "+N more".
- **Focus** a service (`f`) to see its callers, the service and its
  dependencies, one or two hops out.
- **Between** two services (`b`) lists every route between them, direct or
  through one other service.
- **Search** (`/` or Ctrl/Cmd+K) finds services, groups and routes; `l`
  switches to a sortable list view, `?` shows the shortcuts and Esc backs out.
- **Filters** to toggle each edge kind on or off, and a service ↔ repo
  switch that collapses a monorepo's services into one node per
  repository.
- **Drill-down**: click a service to inspect its providers/consumers and
  connected services; click an edge to see its match type, confidence,
  weight, and the underlying contract evidence, with a jump to the
  Contracts view.
- **Gateway-routed links** keep the HTTP line and read "via gateway" on
  hover. A graph short of measured evidence gets one note above the map
  naming the reason.
- A **legend** explaining the edge colours, dash patterns, and the
  health scale.

The map appears once the workspace has at least two indexed
repositories with detected relationships. It shows honest empty states
otherwise.

## Extraction diagnostics

When the cross-repo link count looks low, diagnostics explain why.
Computed alongside contract matching, they report, per repo and contract
type, how many providers and consumers were found, which consumers went
unmatched (and why), and which providers have no consumer at all.

```bash
repowise workspace diagnostics            # human-readable report
repowise workspace diagnostics --json     # raw JSON
repowise workspace diagnostics --repo api # limit to one repo
```

The report covers:

- **Provider / consumer counts** per repo, broken down by contract type.
- **Unmatched consumers**, grouped by reason:
  - `no_provider`, no provider anywhere declares a matching
    route/service/topic.
  - `internal_only`, the only matching provider is in the same repo and
    service, so the call is intra-service and intentionally not surfaced
    as a cross-repo link.
  - `unlinked`, a cross-service provider with a matching id exists, but
    no link formed (a candidate worth inspecting).
  - `external_host`, the call targets a literal third-party host, so it is
    excluded from matching.
  - `ambiguous_provider`, two or more repos serve the call's route and
    neither its host nor its base says which one it reaches, so it links to
    none.
- **HTTP coverage**: calls that linked to another service, calls read,
  and where the read but unlinked ones went. Calls served inside their own
  service are listed apart (`in_service_consumers`), not counted as
  unmatched.
- **Dangling calls**, named per reason with HTTP, gRPC and topics first;
  table reads collapse to one line per repo.
- **Unresolved names**: `http_consumers_unresolved` (calls located whose
  path is not static) and `topic_names_unresolved` (broker calls whose topic
  or queue name the file does not settle).
- **Unrecognised files**: per repo, files that call out over the network or
  use a messaging SDK but produced no contract, a floor on calls no dialect
  recognises.
- **Orphan providers**, endpoints declared but never consumed by any
  repo, one row per repo, service and id (`other_files` lists the other
  declaring files).
- **Weak links**, matched links below the confidence threshold.

The same data is available over REST at `GET /api/workspace/diagnostics`
and is embedded in the system graph artifact's `diagnostics` block.

> **Note**
>
> Diagnostics is the first thing to run when a service you expect to be
> connected shows up isolated on the map. The `unlinked` bucket usually
> points at a route or topic id that almost matched but normalized
> differently on the two sides.
