Package Metrics
Package Metrics
Section titled “Package Metrics”package_metrics measures package architecture quality using Martin-style stability metrics plus package cohesion/cycle diagnostics.
This page documents the current v2 key contract (package_metrics.*).
What It Measures
Section titled “What It Measures”- Module-level coupling and stability (
Ca,Ce, weighted instability) - Package-level cohesion and dependency structure
- Stable-to-unstable dependency anti-patterns (module and package level)
- Package cycles and tangle
- Lakos dependency accumulation (CCD/ACD/NCCD)
- Martin outlier zones (zone of pain, zone of uselessness)
- Optional API surface pressure (when call graph is available)
Output Keys (v2)
Section titled “Output Keys (v2)”Counts and module distributions
Section titled “Counts and module distributions”| Key | Meaning |
|---|---|
package_metrics.module.count | Number of analyzed modules |
package_metrics.package.count | Number of discovered packages |
package_metrics.module.instability.mean | Mean module instability |
package_metrics.module.instability.max | Max module instability |
package_metrics.module.instability.min | Min module instability |
package_metrics.module.instability.median | Median module instability |
package_metrics.module.instability.std_dev | Standard deviation of module instability |
package_metrics.module.ca.mean | Mean afferent coupling (Ca) |
package_metrics.module.ce.mean | Mean efferent coupling (Ce) |
package_metrics.module.ca_weighted.mean | Mean weighted Ca |
package_metrics.module.ce_weighted.mean | Mean weighted Ce |
package_metrics.module.abstractness.mean | Mean abstractness (A) |
package_metrics.module.distance.mean | Mean distance from main sequence (D) |
package_metrics.module.distance.max | Max distance from main sequence |
Dependency risks, cohesion, cycles, Lakos, zones
Section titled “Dependency risks, cohesion, cycles, Lakos, zones”| Key | Meaning |
|---|---|
package_metrics.unstable_dependency.module.count | Stable module -> unstable module dependencies |
package_metrics.unstable_dependency.package.count | Stable package -> unstable package dependencies |
package_metrics.package.cohesion.relational.mean | Mean relational cohesion across packages |
package_metrics.package.cohesion.relational.min | Lowest package cohesion |
package_metrics.package.cohesion.relational.low_count | Packages below configured cohesion threshold |
package_metrics.package.cycle.component_count | Number of cyclic package components |
package_metrics.package.cycle.member_count | Total packages participating in cycles |
package_metrics.package.cycle.largest_component_size | Size of largest package cycle |
package_metrics.package.tangle_index | Fraction of packages in cycles |
package_metrics.package.lakos.ccd | Cumulative component dependency (Lakos CCD) |
package_metrics.package.lakos.acd | Average component dependency (Lakos ACD) |
package_metrics.package.lakos.nccd | Normalized cumulative component dependency (Lakos NCCD) |
package_metrics.zone.pain.count | Stable + concrete modules |
package_metrics.zone.uselessness.count | Unstable + abstract modules |
API surface pressure (optional)
Section titled “API surface pressure (optional)”| Key | Meaning |
|---|---|
package_metrics.api_surface_pressure.mean | Mean module boundary-call pressure |
package_metrics.api_surface_pressure.max | Max module boundary-call pressure |
package_metrics.api_surface_pressure.system | System-wide boundary-call ratio |
Drill-Down Tables
Section titled “Drill-Down Tables”Use table entries for detailed triage (instead of legacy details.* fields):
package_metrics.module.tablepackage_metrics.package.tablepackage_metrics.unstable_dependency.module.tablepackage_metrics.unstable_dependency.package.tablepackage_metrics.package.cycle.components.tablepackage_metrics.zone.tablepackage_metrics.layer.table(only whenlayer_orderis configured)
Main table columns
Section titled “Main table columns”package_metrics.module.table:module,path,package,layer,ca,ce,ca_weighted,ce_weighted,instability,abstractness,distance,zonepackage_metrics.package.table:package,module_count,ca,ce,instability,relational_cohesion,internal_edge_countpackage_metrics.unstable_dependency.module.table:source_module,source_instability,target_module,target_instabilitypackage_metrics.zone.table:module,package,zone,instability,abstractness,distance
Findings Emitted
Section titled “Findings Emitted”This metric emits deterministic findings with rule IDs:
arxo/package-metrics/stable-to-unstable-modulearxo/package-metrics/stable-to-unstable-packagearxo/package-metrics/package-cyclearxo/package-metrics/zone-of-painarxo/package-metrics/zone-of-uselessness
These are included in MetricResult.findings and surfaced in SARIF/JSON reports.
Formulas
Section titled “Formulas”- Module instability:
I = Ce_weighted / (Ca_weighted + Ce_weighted) - Module distance from main sequence:
D = |A + I - 1| - Package instability:
I = Ce / (Ca + Ce) - Relational cohesion:
internal_edge_count / (n * (n - 1))forn > 1, else1.0 - Tangle index:
cyclic_member_count / total_packages - Lakos NCCD:
(CCD - P) / (P * (P - 1))forP > 1, else0.0
Fallbacks:
- If coupling denominator is zero, instability is set to
0.5
Data Requirements and Runtime
Section titled “Data Requirements and Runtime”- Requires import graph and workspace detection.
- Uses type graph when available to compute abstractness (
A); if unavailable, abstractness falls back to0. - Uses call graph when available for
package_metrics.api_surface_pressure.*; otherwise those values are0. - Runtime is linear for most passes (module/package aggregation), plus transitive reachability work for Lakos metrics (
CCD/ACD/NCCD) which can dominate on dense package graphs.
Configuration
Section titled “Configuration”metrics: - id: package_metrics enabled: true config: stable_threshold: 0.30 unstable_threshold: 0.70 cohesion_low_threshold: 0.20 zone_pain_abstractness_max: 0.30 zone_useless_abstractness_min: 0.70 layer_order: ["app", "domain", "infra"] # optional| Option | Default | Purpose |
|---|---|---|
stable_threshold | 0.30 | Max instability considered stable |
unstable_threshold | 0.70 | Min instability considered unstable |
cohesion_low_threshold | 0.20 | Packages below this are marked low cohesion |
zone_pain_abstractness_max | 0.30 | Zone of pain: stable && A <= threshold |
zone_useless_abstractness_min | 0.70 | Zone of uselessness: unstable && A >= threshold |
layer_order | [] | Enables package_metrics.layer.table aggregation |
Policy Examples
Section titled “Policy Examples”Strict CI gate
Section titled “Strict CI gate”metrics: - id: package_metrics enabled: true
policy: invariants: - metric: package_metrics.module.instability.mean op: ">=" value: 0.30 - metric: package_metrics.module.instability.mean op: "<=" value: 0.60 - metric: package_metrics.unstable_dependency.module.count op: "==" value: 0 - metric: package_metrics.package.cycle.component_count op: "==" value: 0Legacy codebase (incremental hardening)
Section titled “Legacy codebase (incremental hardening)”policy: invariants: - metric: package_metrics.unstable_dependency.module.count op: "<=" value: 3 - metric: package_metrics.module.instability.max op: "<=" value: 0.95 - metric: package_metrics.package.cohesion.relational.low_count op: "<=" value: 5Report Walkthrough (JSON excerpt)
Section titled “Report Walkthrough (JSON excerpt)”{ "id": "package_metrics", "data": [ { "key": "package_metrics.module.instability.mean", "value": 0.42 }, { "key": "package_metrics.unstable_dependency.module.count", "value": 1 }, { "key": "package_metrics.package.cycle.component_count", "value": 0 }, { "key": "package_metrics.unstable_dependency.module.table", "columns": ["source_module", "source_instability", "target_module", "target_instability"], "rows": [["src/core/helpers.ts", 0.18, "src/features/cart/service.ts", 0.87]] } ], "findings": [ { "rule_id": "arxo/package-metrics/stable-to-unstable-module", "title": "Stable module depends on unstable module: src/core/helpers.ts -> src/features/cart/service.ts" } ]}Migration from Legacy Keys
Section titled “Migration from Legacy Keys”package_metrics v2 removed legacy top-level keys such as package_metrics.instability_avg.
| Legacy key | v2 replacement |
|---|---|
package_metrics.instability_avg | package_metrics.module.instability.mean |
package_metrics.instability_max | package_metrics.module.instability.max |
package_metrics.instability_min | package_metrics.module.instability.min |
package_metrics.instability_median | package_metrics.module.instability.median |
package_metrics.unstable_dependency_count | package_metrics.unstable_dependency.module.count and package_metrics.unstable_dependency.package.count |
package_metrics.ca_avg | package_metrics.module.ca.mean |
package_metrics.ce_avg | package_metrics.module.ce.mean |
Removed with no direct single-key replacement:
package_metrics.stable_countpackage_metrics.balanced_countpackage_metrics.unstable_count
Use package_metrics.module.table and your configured thresholds to derive those counts.