Class MetricLimits
Acceptable*OrError checkers fire on. Use these;
do NOT re-declare private static final int MAX_* inside a checker or an extractor.
Why this exists. These limits were previously duplicated: each checker held its own
MAX_* constant, and at least one enquiry extractor
(DiWiringExtractor.MAX_INJECTION_FIELDS) held a hand-copied mirror with a javadoc pointing
back at the checker — a textbook DRY drift with no textual fingerprint to grep. Folding them here
means (1) the checker and the MCP/IDE enquiry layer report the same number by construction, and
(2) the enforced quality thresholds become discoverable — an AI can ask "what does EK9 enforce, at
what value, per genus?" via ek9_query_metric_limits, which just serialises ALL.
Values and comparators are transcribed verbatim from the checkers (E11014-E11017, E11040,
E11042, E11043). Genus tables and their exemptions live with the metric here; the two
instance-level LCOM4 exemptions (built-in module, zero-field aggregate) are not genus
metadata and remain in AcceptableCohesionOrError.
Four limits are enforced earlier, by the LEXER as it reads the source: BRACKET_NESTING,
BLOCK_NESTING, EXPRESSION_OPERATORS and MEMBER_ACCESSES. They bound the shape of the
source before anything recurses over it - the parser, its prediction and every later pass - so a pathological source
is an error and not a StackOverflowError (front-end audit FE53, batch B13).
-
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final List<MetricLimit> Every limit, in the order the metric-limits enquiry lists them.static final MetricLimit.ScalarLimitE11042 — component registrations in a single application.static final MetricLimit.ScalarLimitE11010 — arguments in a single call.static final MetricLimit.ScalarLimitE11011 — blocks (indentation levels) open inside each other, counted from the module.static final MetricLimit.ScalarLimitE11061 - boolean literal arguments in one call before the arguments must be named.static final MetricLimit.ScalarLimitE11011 — brackets ((,[and{together) open inside each other.static final MetricLimit.ScalarLimitE11010 — cyclomatic-style complexity of any callable construct (method / operator / function).static final MetricLimit.ScalarLimitE11022 - a class holding this many service fields and no data fields should be a component.static final MetricLimit.ScalarLimitE11021 — cognitive complexity of a callable.static final MetricLimit.RatioLimitE11020 — complexity and size together.static final MetricLimit.GenusLimitE11015 — construct efferent coupling, per genus.static final MetricLimit.ScalarLimitE11013 — complexity of a single expression.static final MetricLimit.ScalarLimitE11013 — operators in one expression, which ends at a comma or at the end of its statement (a line ending in a binary operator carries on).static final MetricLimit.ScalarLimitE11023 - trait methods overridden before a class is judged to forward by hand rather than use 'by'.static final MetricLimit.RatioLimitE11023 - the share of a trait's methods that must be overridden for the same judgement.static final MetricLimit.ScalarLimitE11024 - service fields beside a 'by' delegation make a hybrid of class and component.static final MetricLimit.GenusLimitE11019 — inheritance depth, per genus.static final MetricLimit.ScalarLimitE11043 — distinct injected types used within a single method.static final MetricLimit.ScalarLimitE11040 — injected fields on a single component.static final MetricLimit.GenusLimitE11014 — LCOM4 cohesion, per genus.static final MetricLimit.ScalarLimitE11013 — member accesses (.) in one expression, a chain such asa.b().c().static final MetricLimit.ScalarLimitE11041 - methods of one type injecting the same type before it should be promoted to a facade.static final MetricLimit.ScalarLimitE11025 - data fields that, with the service fields above, mix responsibilities (the Blob).static final MetricLimit.ScalarLimitE11025 - service fields that, with the data fields below, mix responsibilities (the Blob).static final MetricLimit.CompoundLimitE11017 — module cohesion: fires only when disconnected groups exceed BOTH an absolute cap (30) and a relative ratio (88% of constructs), and only once the module has at least 60 constructs.static final MetricLimit.ScalarLimitE11016 — module efferent coupling: distinct external modules a module depends on.static final MetricLimit.ScalarLimitE11027 — declared constructs in a single module.static final MetricLimit.ScalarLimitE11011 — nesting depth of control flow within a callable.static final MetricLimit.ScalarLimitE11012 — statement budget for a function; a standalone unit can be somewhat larger.static final MetricLimit.ScalarLimitE11012 — statement budget for a method; class methods should have a focused responsibility.static final MetricLimit.ScalarLimitE11012 — statement budget for an operator.static final MetricLimit.ScalarLimitE11012 — statement budget for a service operation; a web operation of moderate complexity.static final MetricLimit.ScalarLimitE11010 — aggregated complexity of a type (the sum of its members').static final MetricLimit.ScalarLimitE11054 - type transitions along one chain of calls.static final MetricLimit.ScalarLimitE11062 - arguments in one call before they must be named. -
Method Summary
-
Field Details
-
MODULE_COUPLING
E11016 — module efferent coupling: distinct external modules a module depends on. Fires above 10. -
CONSTRUCT_COUPLING
E11015 — construct efferent coupling, per genus. Default (unlisted genera) is the class threshold. -
LCOM4
E11014 — LCOM4 cohesion, per genus. Traits/records/functions are exempt (single body or intentionally independent operators). Default (unlisted genera) is the class threshold. -
MODULE_COHESION
E11017 — module cohesion: fires only when disconnected groups exceed BOTH an absolute cap (30) and a relative ratio (88% of constructs), and only once the module has at least 60 constructs. -
MODULE_SIZE
E11027 — declared constructs in a single module. Fires above 250.Deliberately generous: it is a god-module backstop, not a design nudge (module cohesion E11017 is the real design signal, and fires on unrelated constructs long before a count does). For calibration, 250 is roughly the 99th percentile of real-world Java packages and ~1.6x the largest module in EK9's own corpus; the JDK's own hand-written packages top out around 160.
Counts SOURCE-DECLARED constructs only. Auto-generated monomorphised parameterised types (
List of Stringand friends) are created in the module that declares the GENERIC, so counting them would let usage elsewhere inflate a module its author does not control - and would make the limit unhittable-by-design for any module exporting a generic. The count comes fromModuleCohesionTracker, which is populated from the parse tree, so synthesised types are excluded by construction rather than by a filter that could drift. -
INJECTION_FIELDS
E11040 — injected fields on a single component. Fires above 4 (Single Responsibility smell). -
APP_REGISTRATIONS
E11042 — component registrations in a single application. Fires above 12. -
INJECTED_TYPES_PER_METHOD
E11043 — distinct injected types used within a single method. Fires at or above 5 (last legal 4). -
CLASS_SERVICE_FIELDS_AS_COMPONENT
E11022 - a class holding this many service fields and no data fields should be a component. Fires at or above 4. -
FORWARDED_METHODS_FOR_BY
E11023 - trait methods overridden before a class is judged to forward by hand rather than use 'by'. Fires at or above 5. -
FORWARDED_METHODS_SHARE_FOR_BY
E11023 - the share of a trait's methods that must be overridden for the same judgement. Fires above 0.70. -
HYBRID_SERVICE_FIELDS
E11024 - service fields beside a 'by' delegation make a hybrid of class and component. Fires at or above 3. -
MIXED_SERVICE_FIELDS
E11025 - service fields that, with the data fields below, mix responsibilities (the Blob). At or above 3. -
MIXED_DATA_FIELDS
E11025 - data fields that, with the service fields above, mix responsibilities (the Blob). At or above 3. -
METHODS_SHARING_INJECTED_TYPE
E11041 - methods of one type injecting the same type before it should be promoted to a facade. Fires at or above 3. -
TYPE_TRANSITIONS
E11054 - type transitions along one chain of calls. Fires above 3. -
BOOLEAN_LITERAL_ARGUMENTS
E11061 - boolean literal arguments in one call before the arguments must be named. Fires at or above 2. -
UNNAMED_ARGUMENTS
E11062 - arguments in one call before they must be named. Fires at or above 4. -
CALLABLE_COMPLEXITY
E11010 — cyclomatic-style complexity of any callable construct (method / operator / function). Fires above 45.Enforced by
AcceptableConstructComplexityOrErrorand re-used byAcceptableCombinedComplexitySizeOrErrorto normalise its complexity ratio — the two MUST agree for that ratio to mean anything. -
TYPE_COMPLEXITY
E11010 — aggregated complexity of a type (the sum of its members'). Deliberately large, so only a type accumulating very many even-moderately-complex methods trips it. Fires above 500. -
COGNITIVE_COMPLEXITY
E11021 — cognitive complexity of a callable. Fires above 35, twice the industry standard of 15: high enough to accommodate genuinely hard code such as parsing, low enough that guarded code at depth 6 (42 points) is over the line. -
BRACKET_NESTING
E11011 — brackets ((,[and{together) open inside each other. Enforced by the lexer. Real code nests them 5-6 deep at most; past 3-4 a reader can no longer match them by eye (Steve, 2026-09-28: "10 and 20 - that is more than enough and protects the compiler and makes code readable and maintainable"). -
BLOCK_NESTING
E11011 — blocks (indentation levels) open inside each other, counted from the module. Enforced by the lexer. Real code reaches about 15: module, construct, method, body, then control flow, switch/case, dynamic classes. -
NESTING_DEPTH
E11011 — nesting depth of control flow within a callable. Fires above 6. -
INHERITANCE_DEPTH
E11019 — inheritance depth, per genus. Slightly stricter than the industry 5-6 because EK9 hasbydelegation as the alternative. Genera not listed are not depth-checked at all. -
EXPRESSION_COMPLEXITY
E11013 — complexity of a single expression. Fires above 15, forcing intermediate variables. -
EXPRESSION_OPERATORS
E11013 — operators in one expression, which ends at a comma or at the end of its statement (a line ending in a binary operator carries on). Enforced by the lexer. Real code uses at most 15 and 99% of expressions 7 or fewer (census of 5,358 sources, 2026-09-28). Coalescing operators are held far tighter still byEXPRESSION_COMPLEXITY: at most 3 of?:, or 2 of<? >?, in a chain. -
MEMBER_ACCESSES
E11013 — member accesses (.) in one expression, a chain such asa.b().c(). Enforced by the lexer. Real code uses at most 7. The dotted name of adefines moduledeclaration is not a member access. -
STATEMENTS_OPERATOR
E11012 — statement budget for an operator. Operators should be single-purpose and brief. -
STATEMENTS_METHOD
E11012 — statement budget for a method; class methods should have a focused responsibility. -
STATEMENTS_FUNCTION
E11012 — statement budget for a function; a standalone unit can be somewhat larger. -
STATEMENTS_SERVICE_OPERATION
E11012 — statement budget for a service operation; a web operation of moderate complexity. -
ARGUMENTS_PER_CALL
E11010 — arguments in a single call. A hard stop, distinct from the 3- and 5-argument points further down that merely ADD to a complexity score rather than failing anything. -
COMBINED_COMPLEXITY_SIZE
E11020 — complexity and size together. Neither operand is a gate on its own: the construct's complexity ratio times its statement ratio must exceed 0.50, so 70% of both passes and 72% of both does not. Expressed as a ratio because there is no count to compare against. -
ALL
Every limit, in the order the metric-limits enquiry lists them.
-