Skip to content

Policy Weakening Review

Policy changes deserve a separate review gate: a green current validation run does not prove that governed scope or a boundary was retained. Configure the change-time comparison severity under analysis:

analysis:
  policy_weakening: error # error, warn, or off

This setting is read only by arch-linter-net policy weakening; it does not change strict or audit validation. For a reviewed brownfield migration, use warn temporarily with a narrow contract/ignore reason that names the migration or issue. The comparison still emits the evidence — it is not baseline debt and it must not be hidden by a broad exception.

Produce the base and current policy-context JSON artifacts from their own repository states, then compare them. Do not pass two policy YAML files from the current checkout and call one historical evidence.

# In the base repository/policy state
arch-linter-net policy context --policy architecture/dependencies.arch.yml --format json > base.json

# In the current repository/policy state
arch-linter-net policy context --policy architecture/dependencies.arch.yml --format json > current.json
arch-linter-net policy weakening --base-context base.json --current-context current.json --format human

The guardrail proves direction for same-ID strict-to-audit/removal, resolved source-set and explicit analysis scope reduction, required-to-optional source sets, source expansions, or rule inputs, matched subtractive exclusions, explicit permission/prohibition inventories, and universal ignores. It recognizes a universal ignore from the context artifact's typed source_type and forbidden_reference matchers, never from the display string. It also treats a newly declared structured architecture waiver, or an extension of an existing waiver's expiry, as semantic weakening. A waiver with the same ID but a changed exact target fingerprint is reported as impact_not_proven: review it as a newly scoped exception rather than assuming the replacement has equivalent impact. Staleness and the current lifecycle state are evaluated by normal validation and reported in its waiver lifecycle section. Changes to type, role, attribute, inheritance, CEL, or public-API selectors are not guessed: without complete evaluator membership evidence they are reported as impact_not_proven for review, with no fabricated affected types. Treat a Shared, Common, or Utils-style exemption as a warning sign to narrow and explain, not as a substitute for fixing code.

Semantic inventory comparison is explicit and shape-aware: only known scalar sets of exact identities may prove a relaxation, while a boolean prohibition has its own true → false direction. Prefixes, globs, call patterns, and cross-field location allowances are impact_not_proven until a containment or trusted effective-membership comparator exists. They are never silently discarded or presented as proof of affected architecture subjects.

analysis.project_include and analysis.project_exclude are globs. A context alone does not prove whether one glob contains another, so a changed glob is also impact_not_proven unless complete resolved project membership evidence is available. Do not treat the addition or removal of a glob string as a semantic scope change.

analysis.target_assemblies, analysis.projects, and analysis.source_roots are authored inputs in the context artifact, not proof of effective runtime scope. Discovery can seed assemblies and roots, and an empty source-root list can select scanner defaults. Any change to these fields is therefore impact_not_proven until a resolved effective-scope artifact is available.