Effect Violations
Effect Violations
Section titled “Effect Violations”Metric ID
Section titled “Metric ID”effect_violations
Overview
Section titled “Overview”effect_violations enforces effect-boundary policy using layer rules and call-graph propagation.
It tracks:
- Direct denied effects in files
- Transitive denied effects reachable through call paths
- Capability leaks at entity level (no direct denied effects, but denied effects exposed transitively)
- Effect hubs (high blast-radius effectful orchestrators)
- Effect coverage gaps (unknown/unscanned files in scope)
Use this metric when you want architectural guarantees such as: “domain code must stay pure” and “effectful boundaries are explicit and controlled.”
Data Requirements
Section titled “Data Requirements”- Call graph
- Effect index
- Entity graph
Key Contract (Current)
Section titled “Key Contract (Current)”| Key | Meaning |
|---|---|
effect_violations.violation_count | direct_violations + transitive_violations + capability_leaks |
effect_violations.direct_violations | Count of direct effect-policy violations |
effect_violations.transitive_violations | Count of transitive effect-policy violations |
effect_violations.capability_leaks | Entity-level leaks of denied transitive effects |
effect_violations.effect_hub_count | Files with outgoing effectful calls above configured threshold |
effect_violations.effect_hub_score | Average outgoing effectful-call count across hubs |
effect_violations.effectful_file_count | Files detected as effectful |
effect_violations.pure_file_count | Files detected as pure |
effect_violations.unknown_file_count | In-scope files with unknown/unscanned effect profile |
effect_violations.coverage_ratio | Share of in-scope files with known effect scan |
effect_violations.health | Weighted health score in [0,1] (higher is better) |
Notes:
violation_countdoes not include hubs or coverage gaps.- Hubs and coverage are modeled through dedicated keys plus findings.
Rule Evaluation Order
Section titled “Rule Evaluation Order”For each candidate effect in scope:
- Applicable rules are selected from
architecture.effect_rules(from_layers/from_paths). - For transitive checks, only rules with
check_transitive: trueare considered. deny_effectswins first.- Then
allow_effectscan allow. - If no rule decides and file belongs to a layer,
layer.allowed_effectsis applied. - If a rule matched scope but no allow matched and no layer allow exists, effect is denied.
Health Formula
Section titled “Health Formula”Definitions:
direct_ratio = direct_violations / scoped_file_counttransitive_ratio = transitive_violations / scoped_file_countcapability_ratio = capability_leaks / scoped_file_counthub_ratio = effect_hub_count / scoped_file_countunknown_penalty = (unknown_file_count / scoped_file_count) * unknown_penalty_weight
Then:
weighted_debt = 0.35*direct_ratio + 0.35*transitive_ratio + 0.15*capability_ratio + 0.10*hub_ratio + 0.05*unknown_penaltyeffect_violations.health = 1 - clamp(weighted_debt, 0, 1)
Coverage:
coverage_ratio = (scoped_file_count - unknown_file_count) / scoped_file_count(or1.0when scope is empty)
Findings Emitted
Section titled “Findings Emitted”effect_violations emits deterministic findings with these rule_id values:
arxo/effect-direct-violationarxo/effect-transitive-violationarxo/effect-capability-leakarxo/effect-coverage-gaparxo/effect-hub
These are returned in MetricResult.findings and appear in JSON/SARIF/HTML reports.
Configuration
Section titled “Configuration”effect_violations behavior is configured under architecture:
architecture: layers: - name: domain paths: ["src/domain/**"] allowed_effects: [] can_depend_on: [] - name: infra paths: ["src/infra/**"] allowed_effects: ["io", "network", "storage", "log"] can_depend_on: ["domain"]
effect_rules: - name: domain-deny-impure-effects from_layers: ["domain"] deny_effects: ["io", "network", "storage"] check_transitive: true max_depth: 6 - name: domain-allow-logging-subtree from_paths: ["src/domain/observability/**"] allow_effects: ["log"] check_transitive: false
effect_violations: hub_threshold: 5 max_witness_paths: 10 unknown_penalty_weight: 0.05 strict_confidence_min: 0.8
metrics: - id: effect_violations enabled: true| Option | Default | Purpose |
|---|---|---|
hub_threshold | 5 | Outgoing effectful-call count needed to classify a file as an effect hub |
max_witness_paths | 10 | Max witness paths/hubs retained for UI and findings |
unknown_penalty_weight | 0.05 | Multiplier for unknown coverage debt in health score |
strict_confidence_min | 0.0 | Ignore effect occurrences below this confidence |
Effect kinds are lowercase strings (for example: io, network, storage, log, time, random, mutation, llm), and can be extended with custom kinds.
Policy Examples
Section titled “Policy Examples”Strict Gate
Section titled “Strict Gate”metrics: - id: effect_violations enabled: true
policy: invariants: - metric: effect_violations.violation_count op: "==" value: 0 message: "No effect boundary violations allowed" - metric: effect_violations.coverage_ratio op: ">=" value: 0.95 message: "Keep effect scan coverage high"Legacy Codebase (Incremental)
Section titled “Legacy Codebase (Incremental)”policy: invariants: - metric: effect_violations.violation_count op: "<=" value: 10 - metric: effect_violations.effect_hub_count op: "<=" value: 5 - metric: effect_violations.health op: ">=" value: 0.80CLI Usage
Section titled “CLI Usage”# Run only effect boundary analysisarxo analyze --metric effect_violations --format json
# Explain metric in CLIarxo metrics explain effect_violations