All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[0.3.1] - 2026-05-21
Added
- Added executable fixture-app architecture examples covering PlantUML conformance, captured slices, function-level call metadata, reusable rules, and graph metrics against real compiled BEAM files.
- Included the fixture example docs, PlantUML diagram, and test module in the Hex package, with the fixture README listed in HexDocs examples.
[0.3.0] - 2026-05-21
Added
use ArchTest, app: ...now automatically scopes assertion, layer, onion, and modulith checks.use ArchTest, freeze: trueauto-freezes assertion wrappers, with stable structured violation baseline keys.ArchTest.Collector.build_graph_from_paths/2, import filters, and function-level%ArchTest.Call{}metadata viacalls/2andcalls_from_path/2.ArchTest.Rulehelpers for reusable rules, ignore filters, assertion, and freeze integration.ArchTest.Modulith.define_slices_by/2for captured namespace slices.ArchTest.PlantUML.enforce/2for component diagram conformance.ArchTest.Metrics.afferent/2,efferent/2,fan_in/2,fan_out/2, anddependency_depth/2.ArchTest.Layers.allow_layer_dependency/3andArchTest.allow_layer_dependency/3for explicit layer-direction exceptions.
Changed
- Empty assertion subjects now fail by default. Use
allow_empty: truewhen an empty subject is intentional. should_have_module_count/2acceptsmin:andmax:aliases forat_least:andat_most:.should_be_free_of_cycles/2now supports bothModuleSetchecks andModulithslice-cycle checks, so documented modulith pipelines work.ArchTest.Collectorfilters now keep dependency graphs closed by removing excluded modules from both graph keys and dependency edges.ArchTest.Collector.calls/2andcalls_from_path/2now filter callers and callees, ignore generated protocol/compiler noise, and report static remote captures plus staticapply/3targets.- Layer, onion, modulith, and convention helpers now consistently forward graph/scope options to the collector.
ArchTest.Metrics.martin/2now computes each module against itself rather than treating the whole matched set as one package.ArchTest.Metrics.coupling/2now treats a binary namespace root and its descendants as one package, and counts distinct external dependencies.ArchTest.Modulith.define_slices_by/2now discovers slices from descendant modules and resolves concrete roots when wildcard segments precede(*).ArchTest.PlantUML.parse_edges/1now ignores line comments and PlantUML block comments.
Fixed
use ArchTest, app: ...now correctly respects per-rule scope overrides forshould_have_module_count/2.use ArchTest, freeze: truenow baselinesshould_have_module_count/2failures and includes semantic scope options (app,apps,paths,include,exclude) in generated freeze IDs.- Freeze update mode no longer baselines empty-subject control failures.
should_only_be_called_by/3now fails on an empty protected object set by default, matching other subject-based assertions.should_have_module_count/3no longer treats assertion options such asrule_id:andallow_empty:as count constraints.should_have_module_count/3no longer treats collector scope options such asapps:,paths:,include:,exclude:, andforce:as count constraints.- Auto-freeze rule IDs for
should_have_module_count/3no longer include non-semanticgraph:data. - Repeated
ArchTest.Rule.ignore/2calls now accumulate filters instead of replacing previous filters for the same field. use ArchTestnow exposes option-awaredefine_layers/2,define_onion/2, anddefine_slices/2helpers.- Documentation examples were corrected for freeze usage, layer exceptions, collector options, metric helpers, and non-overlapping layer patterns.
- Added a 0.2 to 0.3 migration guide with upgrade steps and before/after code examples for app scoping, conventions, empty subjects, freeze baselines, layer patterns, modulith slices, and reusable rules.
- Igniter generators now emit
use ArchTest, app: ..., use safer non-overlapping layer defaults, pass app scope to generated convention checks, and mark optional schema-placement checks withallow_empty: true.
[0.2.1] - 2026-04-10
Fixed
- Compilation without Igniter — mix task files no longer fail with
module Igniter.Mix.Task is not loadedwhen Igniter is not a dependency. All task modules are now wrapped inCode.ensure_loaded?(Igniter.Mix.Task)guards so they are only defined when Igniter is available.
[0.2.0] - 2026-03-08
Added
- Igniter Mix tasks — 8 generators for common architecture patterns:
mix igniter.install arch_test/mix arch_test.install— basic arch test file with cycle checkmix arch_test.gen.phoenix— opinionated Phoenix setup (layers + naming + conventions)mix arch_test.gen.layers— classic web → context → repo layered architecturemix arch_test.gen.onion— onion / hexagonal architecture (domain → application → adapters → web)mix arch_test.gen.modulith— bounded-context slice isolationmix arch_test.gen.naming— naming convention rules (no Managers, schema placement)mix arch_test.gen.conventions— code hygiene checks (noIO.puts,dbg, bareraise)mix arch_test.gen.freeze— freeze baseline for gradual adoption
- Optional Igniter dependency —
{:igniter, "~> 0.7", only: [:dev, :test], optional: true, runtime: false}
[0.1.2] - 2026-03-07
Added
Modulith.all_modules_covered_by/3— asserts that every module under a namespace pattern belongs to a declared slice. Modules that escape slice coverage cause an explicit test failure instead of being silently ignored. Supports:except(list of glob patterns) and:graph(for testability). Also delegated fromArchTestasall_modules_covered_by/2,3.
[0.1.1] - 2026-03-07
Fixed
- OTP version compatibility: tests now use stable fixture modules instead of OTP-version-sensitive stdlib internals, fixing failures on OTP 26/27
- All credo
--strictissues resolved (implicit try,Enum.map_join, negated if/else, nesting depth, cyclomatic complexity)
[0.1.0] - 2026-03-06
Initial release.
Added
- Dependency assertions —
should_not_depend_on/2,should_only_depend_on/2,should_not_be_called_by/2,should_only_be_called_by/2,should_not_transitively_depend_on/2,should_be_free_of_cycles/1,should_not_exist/1 - Naming assertions —
should_reside_under/2,should_have_name_matching/2,should_have_module_count/2 - Behaviour / protocol assertions —
should_implement_behaviour/2,should_not_implement_behaviour/2,should_implement_protocol/2,should_not_implement_protocol/2 - Module attribute assertions —
should_have_attribute/2,should_not_have_attribute/2,should_have_attribute_value/3,should_not_have_attribute_value/3 - Function assertions —
should_export/3,should_not_export/3,should_have_public_functions_matching/2,should_not_have_public_functions_matching/2,should_use/2,should_not_use/2 - Layered architecture —
define_layers/1+enforce_direction/1,define_onion/1+enforce_onion_rules/1 - Modulith / bounded-context isolation —
define_slices/1,allow_dependency/3,enforce_isolation/1,should_not_depend_on_each_other/1 ArchTest.Conventions— pre-built checks:no_io_puts_in/2,no_process_sleep_in/2,no_application_get_env_in/2,no_dbg_in/2,no_raise_string_in/2,no_plug_in/2,all_public_functions_documented/2ArchTest.Metrics— afferent/efferent coupling, instability, abstractness, distance from main sequence (Martin metrics)ArchTest.Freeze— violation baseline freezing for gradual adoption;ARCH_TEST_UPDATE_FREEZE=truemodeArchTest.ModuleSet— fluent module selection DSL: glob patterns,excluding/2,union/2,intersection/2,satisfying/1ArchTest.Pattern— glob pattern compiler with*(single segment) and**(multi-segment) wildcardsArchTest.Collector— BEAM-native dependency graph builder via OTP:xref; works on compiled bytecode, no source parsing- Conventions support for both legacy and modern BEAM debug formats — handles both
:abstract_code(OTP < 24) and:debug_info_v1with:elixir_erlbackend (Elixir 1.14+)