# Architecture conformance

Declare which services may depend on which others and check the live system graph against those rules on every update. Architecture lint with cycle detection.

Workspaces let you declare which services are *allowed* to depend on
which others, then continuously check the live
[system graph](https://docs.repowise.dev/multi-repo/system-map) against those rules. This is
your team's **architecture lint**: the intended architecture, expressed
as code, verified on every update.

On a hosted workspace, rules and repo tags live in the workspace's
**Settings** tab, under **Architecture rules** and **Repo tags**. Use the
same matchers described below. The Conformance tab checks them each time
it loads, so an edit shows there straight away, with no re-index.

## Declaring rules (self-hosted)

On a self-hosted workspace, conformance rules live in a `conformance:` block in the workspace config
(no separate file). Each rule has a `source` matcher, a `target`
matcher, and an `allow` flag:

```yaml
repos:
  - path: web
    alias: frontend
    tags: [ui, edge]
  - path: services/db
    alias: db
    tags: [data]

conformance:
  rules:
    # Deny rules (allow defaults to false): the dependency is a violation.
    - source: frontend
      target: db
      description: The UI must call the API, never the database directly.
    - source: "*"
      target: legacy-payments
    # Tag-based: nothing in the "ui" tier may depend on the "data" tier...
    - source: "tag:ui"
      target: "tag:data"
    # ...except migrations, which are explicitly allowed (an exception).
    - source: migrations
      target: db
      allow: true
```

A **matcher** resolves against service nodes in the system graph:

| Matcher form | Matches |
|--------------|---------|
| `*` | every service |
| `tag:<name>` | every service whose repo declares that tag (see `tags:` on each repo) |
| anything else | a glob over the node id, repo alias, and display name (`frontend`, `api::*`, `*-worker`) |

A rule with `allow: false` (the default) is a **deny** rule: a
structural dependency from a matching source to a matching target is a
violation. A rule with `allow: true` is an **exception** that whitelists
an otherwise-denied edge. Only structural edges (HTTP, gRPC, event,
package, db) are evaluated; behavioral co-change is never treated as a
dependency.

## Dependency cycles

Independently of any rules, conformance detects **circular
dependencies** among services over structural edges (`A → B → … → A`). A
cycle means the services cannot be built, deployed, or reasoned about
independently. Cycle detection runs even with zero rules declared, so
every workspace gets it for free.

Enumeration is bounded: past 20,000 cycles the total is reported as **at
least N** (`total_capped`), and the listed cycles (at most 50) come from a
length-bounded pass, so they are the shortest. The Conformance page shows
"at least N" when capped. When the graph has [too little
evidence](https://docs.repowise.dev/multi-repo/system-map#evidence-state), the verdict says so
instead of reporting zero cycles.

## Using it

### Hosted

The workspace's **Conformance** tab shows the matrix, the violations and
the cycles, and links to the rules in **Settings**. With no rules
declared it says nothing was checked instead of reporting zero
violations.

### CLI (self-hosted)

`repowise workspace check` prints violations and cycles and exits
non-zero when any are found, so it gates CI:

```bash
repowise workspace check          # human-readable report; exit 1 on findings
repowise workspace check --json   # raw report JSON (still exits 1 on findings)
```

It recomputes from the persisted system graph, so editing rules and
re-running picks them up without a full re-index.

### REST (self-hosted)

`GET /api/workspace/conformance` returns the report from the most recent
update, filterable by `repo`.

### MCP

[`get_conformance`](https://docs.repowise.dev/multi-repo/workspace-mcp) exposes violations
and cycles to an agent. It is **opt-in**, outside the default tool
surface, so enable it explicitly if your agent needs it. The
[`get_risk`](https://docs.repowise.dev/mcp/get-risk) PR-mode directive carries
`conformance_violations` and `dependency_cycles` blocks for the findings
the diff's repo participates in regardless of whether `get_conformance`
itself is enabled.

### Conformance view

The web UI's Conformance page renders a **dependency-structure matrix
(DSM)**: services on both axes, each filled cell a dependency tinted by
transport, with rule violations ringed red and cycle cells amber.
Governance panels list the violations and cycles. Violations also badge
the offending edges on the
[System Map](https://docs.repowise.dev/multi-repo/system-map) (toggle **Conformance**),
reusing the same additive overlay as the breaking-change guard.

> **Note**
>
> On a self-hosted workspace, because `repowise workspace check` exits non-zero on any finding, wiring
> it into CI turns your declared architecture into a gate: a pull request
> that introduces a forbidden dependency or a new cycle fails the build.
