use crate::compliance::{
ComplianceDimension, ComplianceDimensionPipeline, CompliancePipelineObservation,
CompliancePipelineSubjectKind, CompliancePolicy, HeatmapContext, HeatmapEntry,
};
use crate::loss::common::{
aggregate_pipeline_observations, pipeline_cohort, reference_scale_for, resolved_calibrator,
};
use crate::metrics::TypeMetrics;
use crate::normalization::{NormalizationCohort, NormalizationContext};
pub(crate) fn state_cardinality_raw(log2_cardinality: f64) -> f64 {
log2_cardinality.max(0.0)
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn state_cardinality_observations(
types: &[TypeMetrics],
functions: &[crate::metrics::FunctionMetrics],
type_normalizer: crate::normalization::Normalizer,
type_calibrator: crate::calibration::Calibrator,
function_normalizer: crate::normalization::Normalizer,
function_calibrator: crate::calibration::Calibrator,
semantic: Option<&crate::semantic::SemanticOverlay>,
) -> Vec<CompliancePipelineObservation> {
let mut observations: Vec<CompliancePipelineObservation> =
Vec::with_capacity(types.len() + functions.len());
for t in types {
let cardinality_log2 = semantic
.and_then(|s| s.type_cardinality(&t.file, &t.module_path, &t.name))
.unwrap_or(t.state_cardinality_log2);
let raw = state_cardinality_raw(cardinality_log2);
let calibrated = type_calibrator.calibrate(type_normalizer.normalize(raw));
observations.push(CompliancePipelineObservation {
kind: CompliancePipelineSubjectKind::Type,
file: t.file.clone(),
line: t.line,
name: t.name.clone(),
detail: format!("log2 cardinality {cardinality_log2:.1}"),
cohort: Some(NormalizationCohort::StateCardinalityType),
size_hint: t.total_fields.max(1) as f64,
raw,
normalized: Some(calibrated.normalized),
calibrated_score: calibrated.score,
scope_path: t.scope_path.clone(),
});
}
for f in functions
.iter()
.filter(|f| !f.is_test && f.internal_state_cardinality_log2 > 0.0)
{
let cardinality_log2 = semantic
.and_then(|s| s.function_cardinality(&f.file, &f.module_path, &f.name, f.line))
.unwrap_or(f.internal_state_cardinality_log2);
let raw = state_cardinality_raw(cardinality_log2);
let calibrated = function_calibrator.calibrate(function_normalizer.normalize(raw));
observations.push(CompliancePipelineObservation {
kind: CompliancePipelineSubjectKind::Function,
file: f.file.clone(),
line: f.line,
name: f.name.clone(),
detail: format!("fn internal log2 cardinality {cardinality_log2:.1}"),
cohort: Some(NormalizationCohort::StateCardinalityFunction),
size_hint: f.lines.max(1) as f64,
raw,
normalized: Some(calibrated.normalized),
calibrated_score: calibrated.score,
scope_path: f.scope_path.clone(),
});
}
observations
}
pub(crate) fn state_cardinality_compliance(
types: &[TypeMetrics],
functions: &[crate::metrics::FunctionMetrics],
policy: &CompliancePolicy,
normalization_context: &NormalizationContext,
semantic: Option<&crate::semantic::SemanticOverlay>,
) -> ComplianceDimension {
let reference_scale = reference_scale_for(policy, NormalizationCohort::StateCardinalityType);
let type_normalizer = policy.normalization.normalizer_for(
normalization_context,
NormalizationCohort::StateCardinalityType,
reference_scale,
);
let function_normalizer = policy.normalization.normalizer_for(
normalization_context,
NormalizationCohort::StateCardinalityFunction,
reference_scale,
);
let type_calibrator = resolved_calibrator(policy, NormalizationCohort::StateCardinalityType);
let function_calibrator =
resolved_calibrator(policy, NormalizationCohort::StateCardinalityFunction);
let rule_label = "normalize(log2_card)";
let observations = state_cardinality_observations(
types,
functions,
type_normalizer,
type_calibrator,
function_normalizer,
function_calibrator,
semantic,
);
let item_count = observations.len();
let score = aggregate_pipeline_observations(
policy.aggregation.state_cardinality_aggregation,
&observations,
);
ComplianceDimension {
name: "state_cardinality".into(),
score,
item_count,
rule: format!(
"{} type={:?}, fn={:?}; calibrate type={:?}, fn={:?}; aggregate with {:?}",
rule_label,
type_normalizer,
function_normalizer,
type_calibrator,
function_calibrator,
policy.aggregation.state_cardinality_aggregation
),
pipeline: ComplianceDimensionPipeline {
cohorts: vec![
pipeline_cohort(
NormalizationCohort::StateCardinalityType,
reference_scale,
type_normalizer,
type_calibrator,
),
pipeline_cohort(
NormalizationCohort::StateCardinalityFunction,
reference_scale,
function_normalizer,
function_calibrator,
),
],
artifact_aggregation: Some(policy.aggregation.state_cardinality_aggregation),
aggregated_score: score,
observations,
},
}
}
pub(crate) fn emit_state_cardinality_heatmap(
ctx: &HeatmapContext<'_>,
entries: &mut Vec<HeatmapEntry>,
) {
crate::loss::common::emit_observation_based_heatmap(
"state_cardinality",
ctx.policy.aggregation.state_cardinality_aggregation,
ctx,
entries,
);
}