Architecture metrics¶
Metric declarations let you inspect stable architecture values before you set a
budget. They are optional, read-only policy data: measure reports their
values, while budget contracts participate in ordinary strict or audit
validation.
topology:
subject_kind: namespace
mode: exhaustive
scope:
selectors:
- namespace: MyApp
nodes:
- id: application
mappings:
- namespace: MyApp.Application
- id: infrastructure
mappings:
- namespace: MyApp.Infrastructure
metrics:
- id: application-outgoing
kind: outgoing_component_count
topology_node: application
- id: application-footprint
kind: component_footprint_count
topology_node: application
unit: project
contracts:
strict_metric_budgets:
- id: application-outgoing-limit
metric: application-outgoing
maximum: 3
audit_metric_budgets:
- id: application-minimum-footprint
metric: application-footprint
minimum: 2
The closed metric kinds are:
outgoing_component_countincoming_component_countexternal_dependency_group_countcomponent_footprint_count(requiresunit: projectorunit: assembly)topology_type_count(requires asubject_kind: typetopology)public_contract_surface_count(requirespublic_api_surface: <contract-id>)
A project footprint uses the canonical project ownership resolved by the
analysis snapshot. Configure the policy's project/solution discovery inputs
when you need that metric; ArchLinterNet reports an unassessable scope rather
than treating an assembly name as a project identity.
Absolute budgets¶
Budget contracts reference a declared metric by ID; they do not repeat its kind
or subject selector. Place an enforcing rule in strict_metric_budgets and an
informational rule in audit_metric_budgets. Each rule needs a unique id and
at least one non-negative integer bound:
minimumfails only when the measured value is lower;maximumfails only when the measured value is higher;- both are allowed when
minimumis less than or equal tomaximum.
The bounds are inclusive, so a value equal to a bound passes. A budget uses the
same value, effective scope, and canonically ordered contributors shown by
measure; it does not calculate another metric. A passing budget creates no
finding, while a violation identifies the value, breached limit, metric
subject, and contributors through the normal Human, JSON, SARIF, Testing, and
baseline paths.
measure remains the best first step for choosing a reviewed limit. If its
required metric scope is unassessable because of missing, unmapped, ambiguous,
stale, or unexpected-empty evidence, validation projects the same shared
applicability evidence for the budget instead of treating a partial low count
as a passing result.
Baseline-relative budgets¶
A metric budget can ratchet growth from a reviewed scalar value instead of
declaring only an absolute bound. Relative budgets remain ordinary strict or
audit contracts: put a blocking budget in strict_metric_budgets and an
informational one in audit_metric_budgets. baseline_mode is the relative
dimension; strict/audit are still the enforcement modes. There is no third
ratchet mode.
The supported modes are:
no_worse_than_baselineallows no increase over the reviewed value (allowed delta0);max_deltaallows an increase up to the required non-negative integermax_delta.
The existing maximum can optionally remain as an absolute safety cap. The
effective threshold is the lower of the reviewed value plus the allowed delta
and that cap, when a cap is present. Relative budgets must not declare
minimum; absolute budgets without baseline_mode keep their existing
minimum/maximum behavior.
For example, these budgets share the metric definitions above:
contracts:
strict_metric_budgets:
- id: application-outgoing-ratchet
metric: application-outgoing
baseline_mode: no_worse_than_baseline
audit_metric_budgets:
- id: application-footprint-ratchet
metric: application-footprint
baseline_mode: max_delta
max_delta: 2
maximum: 20
The reviewed values live in a version-3 baseline's separate top-level
metric_baselines collection. A scalar entry is identified only by its
canonical metric definition and subject fields, not by a budget ID, display
text, contributor label, or finding identity:
version: 3
baseline:
strict_metric_budgets: []
audit_metric_budgets: []
metric_baselines:
- metric_identity_version: 1
metric_id: application-outgoing
metric_kind: outgoing_component_count
native_subject: application
effective_scope: application
value: 3
- metric_identity_version: 1
metric_id: application-footprint
metric_kind: component_footprint_count
native_subject: application
unit: project
effective_scope: application
value: 2
unit is included when the metric definition declares one; omit it for an
unqualified metric. native_subject and effective_scope are the canonical
values reported by measure, so copy them from that output rather than
inventing display labels. The migration baseline guide
describes how to capture and review these entries.
A relative budget is assessable only when its selected baseline contains one matching scalar entry. A missing entry, unsupported identity version, or change to the metric kind, native subject, unit, or effective scope is stale or otherwise unassessable baseline evidence. It fails closed: the value is not treated as zero, the budget does not pass, and the entry is never used as a finding-level ignore. Ordinary validation does not refresh a reviewed value.
Run baseline generate explicitly after reviewing the current measurement to
capture a complete scalar value. baseline update and baseline prune are
finding-debt lifecycle commands; they preserve existing metric_baselines
values and never add, replace, or recalculate them. A new reviewed value
requires another explicit generation or a reviewed manual edit.
Run the report with:
arch-linter-net measure --policy architecture/dependencies.arch.yml
arch-linter-net measure --format json --max-contributors 10
Each value is a cardinality of canonical, ordinally ordered contributors.
Repeated references do not inflate a value; component relations are direct, not
transitive; self edges do not contribute. A zero is trustworthy only when the
required scope is complete. Unmapped, ambiguous, stale, missing, or otherwise
incomplete required evidence is reported through the shared applicability model
with no numeric value, and measure exits 2 rather than presenting a partial
low count as a clean result.