Capabilities¶
This page summarizes what ArchLinterNet can and cannot validate for AI policy authors. The machine-readable version is archlinternet.capabilities.json.
Supported policy structure¶
The policy file is usually architecture/dependencies.arch.yml and contains:
version: current value is1.name: human-readable policy name.layers: named namespace-prefix or constrained glob layer definitions.external_dependencies: named vendor/framework dependency groups.legacy_runtime_layers: optional namespace prefixes used by dependency contracts.analysis: target assemblies, assembly search paths, optional source roots, condition sets, and default condition set.contracts: strict and audit contract groups.
Supported contract families¶
| Family | Strict group | Audit group | Validates |
|---|---|---|---|
| Dependency | strict |
audit |
Source layer must not reference forbidden layers. |
| Layer order | strict_layers |
audit_layers |
Dependencies point from outer layers toward inner layers. |
| Allow-only | strict_allow_only |
audit_allow_only |
Source layer references only itself and allowed first-party layers. |
| Cycle | strict_cycles |
audit_cycles |
Selected layers do not form directed cycles. |
| Acyclic sibling | strict_acyclic_siblings |
audit_acyclic_siblings |
Direct sibling namespaces under ancestor namespaces do not form dependency cycles. |
| Method body | strict_method_body |
audit_method_body |
Source layer does not call forbidden APIs. |
| asmdef | strict_asmdef |
audit_asmdef |
Unity .asmdef references avoid editor refs or forbidden prefixes. |
| Independence | strict_independence |
audit_independence |
Selected layers do not reference each other. |
| Assembly independence | strict_assembly_independence |
audit_assembly_independence |
Selected .NET assemblies do not directly reference each other. |
| Assembly dependency | strict_assembly_dependency |
audit_assembly_dependency |
Source assembly does not directly reference forbidden assemblies. |
| Assembly allow-only | strict_assembly_allow_only |
audit_assembly_allow_only |
Source assembly directly references only itself and explicitly allowed declared assemblies. |
| Project metadata | strict_project_metadata |
audit_project_metadata |
Selected discovered projects preserve required metadata, restrict friend assemblies, and avoid forbidden project references. |
| Protected surface | strict_protected |
audit_protected |
Protected layers are referenced only by explicitly allowed importers. |
| External dependency | strict_external |
audit_external |
Source layer does not reference forbidden vendor/framework dependency groups. |
| External allow-only | strict_external_allow_only |
audit_external_allow_only |
Source layer references only explicitly allowed vendor/framework dependency groups. |
| Layer template | strict_layer_templates |
audit_layer_templates |
Reusable layer order applied to multiple containers. |
| Type placement | strict_type_placement |
audit_type_placement |
A selected architectural role resides in a declared layer/namespace/project/assembly and/or carries a declared naming suffix/prefix. |
| Public API surface | strict_public_api_surface |
audit_public_api_surface |
An assembly's exported public/protected/protected-internal types and members match a declared signature allowlist. |
| Attribute usage | strict_attribute_usage |
audit_attribute_usage |
A declared attribute/marker type appears only in (or never in) a declared layer/namespace/project/assembly. |
| Inheritance | strict_inheritance |
audit_inheritance |
Types in a declared source layer/namespace do not inherit (directly or transitively) from declared forbidden base types. |
| Interface implementation | strict_interface_implementation |
audit_interface_implementation |
Implementations of declared interfaces reside only in (or never in) declared layers/namespaces/projects/assemblies. |
| Composition | strict_composition |
audit_composition |
Composition-root/service-locator API calls occur only from a declared composition boundary (layers/namespaces/projects/assemblies). |
| Coverage | strict_coverage |
audit_coverage |
First-party namespaces, discovered projects, and resolved assemblies are covered by a layer, template expansion, or explicit exclusion. |
Matching semantics¶
Layer namespace values match exact namespaces and child namespaces. For example, MyCompany.Product.Domain matches MyCompany.Product.Domain and MyCompany.Product.Domain.Models.
Layer namespace also supports constrained glob patterns using * as a full namespace segment. For example, MyCompany.Product.Features.* matches MyCompany.Product.Features.Audio and descendants such as MyCompany.Product.Features.Audio.Player.
namespace_suffix can narrow a layer to a suffix such as Contracts or Models. When namespace contains a glob, the suffix is position-fixed immediately after the resolved namespace pattern.
external_dependencies.namespace_prefixes match exact namespaces and child namespaces. external_dependencies.type_prefixes match full referenced type names by prefix.
ignored_violations should be exact and narrow. Broad patterns should be treated as temporary migration debt and reviewed by a human.
Type placement types_matching fields (name_suffix, name_prefix, namespace, layer, base_type, implements_interface, has_attribute) combine with AND semantics — every populated field must match. There is no regex or expression-language selector. must_reside_in_projects resolves to assembly-name matching via project discovery (see Type placement contracts); it is not physical .csproj-membership tracking.
Public API surface declared_api entries are normalized signature strings (<kind> <FullyQualifiedName>[(<param types>)][: <member type>]); generic type/method parameters are rendered positionally (!N/!!N), not by their source-declared name. forbid_public_constants_unless_declared is an independent, stricter check layered on top of the general declaration — an exported const field can still be forbidden even when its full signature is already in declared_api, unless its fully-qualified name is also in allowed_public_constants. See Public API surface contracts for the full grammar.
Attribute usage attributes entries match an attribute type's fully-qualified name exactly (ordinal); attribute_prefixes entries match by ordinal StartsWith. Every declared member is scanned regardless of visibility (unlike public API surface), because markers such as [SerializeField] and [Authorize] commonly decorate non-public members. allowed_only_in_* forms an allow-list (violation if the matched attribute's enclosing type satisfies none of it); forbidden_in_* forms a deny-list (violation if it satisfies any of it); a contract must declare at least one attribute selector and at least one location expectation. See Attribute usage contracts — this family does not implement required-marker ("must carry attribute X") checks; those are deferred to a documented follow-up.
Inheritance forbidden_base_types entries match a base type's fully-qualified name exactly (ordinal); forbidden_base_type_prefixes entries match by ordinal StartsWith. The full base-class chain is walked (transitive inheritance is detected), constructed generic base types are matched by their generic type definition's CLR name (arity suffix, e.g. App.Repository`1), and interface implementations are never matched by this family. A contract must declare at least one source surface selector (source_layers/source_namespaces) and at least one base type selector. See Inheritance contracts.
Interface implementation interfaces entries match an interface's fully-qualified name exactly (ordinal); interface_prefixes entries match by ordinal StartsWith. A non-interface type matches through its full interface set, including interfaces inherited via base classes; interface types extending a selected interface are never violations. allowed_only_in_*/forbidden_in_* follow the same allow-list/deny-list semantics as attribute usage, and a contract must declare at least one interface selector and at least one location expectation. This is static metadata analysis, not runtime dependency-injection resolution. See Interface implementation contracts.
Composition forbidden_apis entries use the same call-pattern vocabulary as method-body contracts (member names, Type.Member names, fully qualified members, namespace/type prefixes). Every loaded type outside the allowed_only_in_* composition boundary is scanned reflection/IL-only for calls matching a forbidden_apis entry; a type inside the boundary is never scanned. A contract must declare at least one forbidden_apis entry and at least one allowed_only_in_* boundary entry — unlike interface implementation and attribute usage, there is no separate forbidden_in_* deny-list, since everything outside the allow-list is forbidden by definition. This is static reflection/IL call-site detection, not runtime dependency-injection resolution — it does not prove every service is registered correctly. See Composition contracts.
Project metadata contracts target discovered project paths (projects) rather than assemblies or layers. required_properties and forbidden_properties compare exact scalar MSBuild property values, including statically inherited values from the nearest readable Directory.Build.props chain. allowed_friend_assemblies compares exact InternalsVisibleTo names from project-file items and source-level assembly attributes, and forbidden_project_references uses project-path glob matching against declared ProjectReference targets. This is static project metadata analysis only — not full MSBuild evaluation or runtime/package validation. See Project metadata contracts.
Strict versus audit¶
Strict contracts are blocking rules for current no-new-debt gates. Audit contracts are diagnostic rules for discovery, future-state architecture, and migration planning.
Coverage findings also honor analysis.coverage:
error: findings fail validation;warn: findings are reported but do not fail validation;off: findings are suppressed.
Current limit: scope: namespace, scope: rule_input, scope: project,
scope: assembly, and scope: dependency_edge are implemented for coverage
contracts. scope: dependency_edge declares between (declared-layer-name
pairs) and classifies observed first-party namespace-to-namespace edges per
pair as covered (governed by an existing dependency, layer, independence,
allow-only, protected, or expanded layer-template contract), excluded, or
uncovered. Layer pairs absent from every between list are not evaluated.
Supported adoption helpers¶
ArchLinterNet supports generated baselines for existing repositories:
arch-linter-net baseline generate \
--config architecture/dependencies.arch.yml \
--output architecture/baseline.arch.yml
Baselines are frozen debt, not a way to hide new violations.
Not supported¶
ArchLinterNet does not currently validate:
- runtime behavior or dynamic dependency injection resolution;
- security policy, authorization, or data access permissions;
- code ownership or review ownership;
- semantic data-flow analysis;
- third-party package internals;
- unrestricted namespace pattern systems;
- unrestricted custom contract families outside the documented YAML schema;
- arbitrary YAML fields such as
severity,from,to,regex,owner, or custom rule groups unless the schema documents them.
Do not author YAML fields for unsupported capabilities. Track future needs in a separate proposal instead.