brick/docs/architecture/policy.md

3.3 KiB

Declarative architecture policy

Brick policy is a small, versioned consumer of the canonical building graph. It extends brick check; it does not introduce a second gate engine or infer relationships that are absent from the model.

Policy schema 1

A policy is JSON with exactly three top-level fields. Unknown fields and unknown rule kinds fail closed.

{
  "policy_schema_version": 1,
  "scope": {
    "path": ".",
    "excluded_directories": [],
    "p4_frontend": "lexical"
  },
  "rules": [
    {
      "kind": "forbid-dependency",
      "id": "api-must-not-call-storage",
      "source_path_prefix": "src/api",
      "target_path_prefix": "src/storage",
      "edge_kinds": ["calls", "imports"],
      "max_matches": 0
    }
  ]
}

The policy scope must exactly match the building's schema-v4 scan scope, including the selected P4 frontend and the sorted, unique exclusion list. Scope paths and rule prefixes must be normalized repository-relative paths; absolute or drive-qualified paths, backslashes, empty components, . components, and .. are rejected (. alone means the entire repository).

Rule IDs are required and unique. Edge kinds are required, unique, and limited to canonical dependency kinds: calls, imports, and inherits. Containment, definition, finding/Flags, and unknown wire values cannot be relabeled as architecture dependencies by policy.

Path prefixes are component-aware: src/api matches src/api/handler.rs but not src/apiary.rs. max_matches is explicit; zero forbids every matching relationship, while a larger value expresses a bounded exception without hiding the matched edges.

Evaluation and evidence

Before evaluation, Brick validates the building schema and exactly-one repository identity, verifies exact scope equality, and rejects duplicate node or edge IDs plus edges with missing source or target nodes. Rules are evaluated in rule-ID order and matched edges in stable edge-ID order.

Policy never changes evidence confidence or lane. Each match in the result contains the complete canonical edge plus complete source and target nodes, so backend, Syntactic/Heuristic/Imported/Symbolic lane, producer-local confidence, attributes, and provenance remain inspectable.

Policy result JSON has policy_result_schema_version = 1 and records the input policy schema, building schema, absolute execution root, stable repository ID, scope, overall pass state, and every rule's ordered matches.

brick check integration

brick check build/brick/current.json --min-score 70 \
  --policy architecture-policy.json \
  --policy-result-json build/brick/policy-result.json

--policy-result-json requires --policy. Complete results are written before a rule failure is returned. Policy failures join the existing score, cycle, unresolved-dependency, and optional structural-diff failures under the same structural gate failed result. Without --policy, existing check behavior is unchanged.

Checked-in positive, clean-negative, and unknown-wire fixtures live in tests/fixtures/policy/. This initial slice supports repository-relative forbidden dependency boundaries only. Diff-count budgets remain the explicit stable-ID diff gates described in docs/architecture/structural-diff.md; future policy rule kinds must be versioned rather than inferred from extra JSON keys.