Skip to main content

dsfb_semiconductor/
failure_driven.rs

1use crate::baselines::{BaselineSet, EwmaFeatureTrace};
2use crate::cohort::{MissedFailureDiagnosticRow, OperatorBurdenContributionRow};
3use crate::grammar::{FeatureGrammarTrace, GrammarReason, GrammarSet, GrammarState};
4use crate::metrics::{BenchmarkMetrics, PerFailureRunSignal};
5use crate::precursor::{DsaEvaluation, DsaFeatureTrace, DsaPolicyState, PerFailureRunDsaSignal};
6use crate::preprocessing::PreparedDataset;
7use crate::residual::{ResidualFeatureTrace, ResidualSet};
8use crate::semiotics::{
9    DsfbMotifClass, FeatureMotifTrace, GroupDefinitionRecord, MotifSet, ScaffoldSemioticsArtifacts,
10    SemanticLayer,
11};
12use crate::signs::{FeatureSigns, SignSet};
13use serde::Serialize;
14use std::collections::{BTreeMap, BTreeSet};
15
16const MAX_FAILURE_CASE_FEATURES: usize = 5;
17const MAX_FAILURE_INDEX_ACTIVITY: usize = 3;
18const MAX_MINIMAL_HEURISTICS: usize = 20;
19
20#[derive(Debug, Clone, Copy)]
21struct FeatureRoleLockSpec {
22    feature_name: &'static str,
23    initial_role: &'static str,
24    preferred_semantic_labels: &'static [&'static str],
25    preferred_grounded_motif_types: &'static [&'static str],
26    preferred_grammar_states: &'static [&'static str],
27    revised_role: Option<&'static str>,
28}
29
30const FEATURE_ROLE_LOCK: &[FeatureRoleLockSpec] = &[
31    FeatureRoleLockSpec {
32        feature_name: "S059",
33        initial_role: "primary recurrent-boundary precursor",
34        preferred_semantic_labels: &["recurrent_boundary_approach", "pre_failure_slow_drift"],
35        preferred_grounded_motif_types: &["boundary_grazing", "slow_drift_precursor"],
36        preferred_grammar_states: &["BoundaryGrazing", "SustainedDrift"],
37        revised_role: Some("persistence-gated recurrent-boundary review feature"),
38    },
39    FeatureRoleLockSpec {
40        feature_name: "S123",
41        initial_role: "transition / instability feature",
42        preferred_semantic_labels: &["transition_excursion", "persistent_instability_cluster"],
43        preferred_grounded_motif_types: &["persistent_instability", "burst_instability"],
44        preferred_grammar_states: &["TransientViolation", "PersistentViolation"],
45        revised_role: Some("transition / instability support feature"),
46    },
47    FeatureRoleLockSpec {
48        feature_name: "S133",
49        initial_role: "candidate slow-drift precursor",
50        preferred_semantic_labels: &["pre_failure_slow_drift"],
51        preferred_grounded_motif_types: &["slow_drift_precursor"],
52        preferred_grammar_states: &["SustainedDrift"],
53        revised_role: Some("semantically ambiguous review-only candidate"),
54    },
55    FeatureRoleLockSpec {
56        feature_name: "S540",
57        initial_role: "burst-support corroborator",
58        preferred_semantic_labels: &["transition_cluster_support"],
59        preferred_grounded_motif_types: &["burst_instability"],
60        preferred_grammar_states: &["TransientViolation", "PersistentViolation"],
61        revised_role: Some("review-only burst-support corroborator"),
62    },
63    FeatureRoleLockSpec {
64        feature_name: "S128",
65        initial_role: "co-burst corroborator",
66        preferred_semantic_labels: &["transition_cluster_support"],
67        preferred_grounded_motif_types: &["burst_instability"],
68        preferred_grammar_states: &["TransientViolation", "PersistentViolation"],
69        revised_role: Some("review-only co-burst corroborator"),
70    },
71    FeatureRoleLockSpec {
72        feature_name: "S104",
73        initial_role: "watch-only sentinel",
74        preferred_semantic_labels: &["watch_only_boundary_grazing"],
75        preferred_grounded_motif_types: &["boundary_grazing", "noise_like"],
76        preferred_grammar_states: &["BoundaryGrazing"],
77        revised_role: Some("watch-only nuisance sentinel"),
78    },
79    FeatureRoleLockSpec {
80        feature_name: "S134",
81        initial_role: "recall-rescue feature",
82        preferred_semantic_labels: &[],
83        preferred_grounded_motif_types: &["recovery_pattern", "persistent_instability"],
84        preferred_grammar_states: &["BoundaryGrazing", "Recovery"],
85        revised_role: Some("bounded recall-rescue feature"),
86    },
87    FeatureRoleLockSpec {
88        feature_name: "S275",
89        initial_role: "recall-rescue feature",
90        preferred_semantic_labels: &[],
91        preferred_grounded_motif_types: &["recovery_pattern", "persistent_instability"],
92        preferred_grammar_states: &["BoundaryGrazing", "Recovery"],
93        revised_role: Some("bounded recall-rescue feature"),
94    },
95];
96
97#[derive(Debug, Clone, Serialize)]
98pub struct FailuresIndex {
99    pub total_failure_count: usize,
100    pub missed_failure_ids: Vec<usize>,
101    pub entries: Vec<FailureIndexEntry>,
102}
103
104#[derive(Debug, Clone, Serialize)]
105pub struct FailureIndexEntry {
106    pub failure_id: usize,
107    pub timestamp_or_run_index: String,
108    pub timestamp: String,
109    pub detected_by_current_dsa: bool,
110    pub detected_by_dsa: bool,
111    pub detected_by_optimized_dsa: bool,
112    pub detected_by_ewma: bool,
113    pub detected_by_threshold: bool,
114    pub detected_by_cusum_if_present: bool,
115    pub detected_by_run_energy_if_present: bool,
116    pub detected_by_pca_fdc_if_present: bool,
117    pub lead_time_dsa: Option<usize>,
118    pub lead_time: Option<usize>,
119    pub lead_time_threshold: Option<usize>,
120    pub lead_time_ewma: Option<usize>,
121    pub lead_time_cusum: Option<usize>,
122    pub lead_time_run_energy: Option<usize>,
123    pub lead_time_pca_fdc: Option<usize>,
124    pub optimized_lead_time: Option<usize>,
125    pub feature_activity_summary: Vec<FeatureActivitySummary>,
126}
127
128#[derive(Debug, Clone, Serialize)]
129pub struct FeatureActivitySummary {
130    pub feature_index: usize,
131    pub feature_name: String,
132    pub max_dsa_score: f64,
133    pub max_policy_state: String,
134    pub motif_hits: usize,
135    pub pressure_hits: usize,
136}
137
138#[derive(Debug, Clone, Serialize)]
139pub struct FailureCaseReport {
140    pub failure_id: usize,
141    pub failure_timestamp: String,
142    pub baseline_detected_by_dsa: bool,
143    pub optimized_detected_by_dsa: bool,
144    pub detected_by_ewma: bool,
145    pub detected_by_threshold: bool,
146    pub baseline_dsa_lead_runs: Option<usize>,
147    pub optimized_dsa_lead_runs: Option<usize>,
148    pub ewma_lead_runs: Option<usize>,
149    pub threshold_lead_runs: Option<usize>,
150    pub exact_miss_rule: String,
151    pub failure_stage: String,
152    pub failure_explanation: String,
153    pub why_dsfb_missed: String,
154    pub missed_reason_class: String,
155    pub ewma_detection_explanation: String,
156    pub threshold_detection_explanation: String,
157    pub why_ewma_succeeded_or_failed: String,
158    pub why_threshold_succeeded_or_failed: String,
159    pub top_contributing_features: Vec<FailureCaseFeatureDetail>,
160}
161
162#[derive(Debug, Clone, Serialize)]
163pub struct FailureCaseFeatureDetail {
164    pub feature_index: usize,
165    pub feature_name: String,
166    pub behavior_classification: String,
167    pub initial_behavior_classification: String,
168    pub ranking_score_proxy: f64,
169    pub max_dsa_score: f64,
170    pub max_policy_state: String,
171    pub motif_hypothesis: String,
172    pub initial_motif_hypothesis: String,
173    pub dominant_dsfb_motif: String,
174    pub dominant_grammar_state: String,
175    pub semantic_labels: Vec<String>,
176    pub failure_stage: String,
177    pub failure_explanation: String,
178    pub residual_trajectory: Vec<f64>,
179    pub drift_trajectory: Vec<f64>,
180    pub slew_trajectory: Vec<f64>,
181    pub motif_timeline: Vec<String>,
182    pub grammar_state_timeline: Vec<String>,
183    pub grammar_trajectory: Vec<String>,
184}
185
186#[derive(Debug, Clone, Serialize)]
187pub struct MissedFailurePriorityRow {
188    pub failure_id: usize,
189    pub timestamp: String,
190    pub exact_miss_rule: String,
191    pub top_feature_name: Option<String>,
192    pub signal_strength: f64,
193    pub feature_concentration: f64,
194    pub separation_from_noise: f64,
195    pub recoverability_estimate: f64,
196    pub priority_score: f64,
197}
198
199#[derive(Debug, Clone, Serialize)]
200pub struct FeatureToMotifRecord {
201    pub feature_index: usize,
202    pub feature_name: String,
203    pub initial_role: String,
204    pub motif_type: String,
205    pub failure_behavior_justification: String,
206    pub pass_behavior_justification: String,
207    pub justification: String,
208}
209
210#[derive(Debug, Clone, Serialize)]
211pub struct NegativeControlReport {
212    pub pass_run_count: usize,
213    pub pass_run_false_activation_count: usize,
214    pub false_activation_rate: f64,
215    pub pass_run_false_episode_count: usize,
216    pub false_episode_rate: f64,
217    pub review_escalate_points_on_pass_runs: usize,
218    pub review_escalate_episodes_on_pass_runs: usize,
219    pub clean_window_count: usize,
220    pub clean_window_false_activation_count: usize,
221    pub clean_window_false_activation_rate: f64,
222    pub clean_window_false_episode_count: usize,
223    pub clean_window_false_episode_rate: f64,
224    pub review_escalate_points_on_clean_runs: usize,
225    pub review_escalate_episodes_on_clean_runs: usize,
226}
227
228#[derive(Debug, Clone, Serialize)]
229pub struct FeatureRoleValidationRow {
230    pub feature_id: String,
231    pub initial_role: String,
232    pub initial_motif: String,
233    pub supported_or_revised_or_rejected: String,
234    pub failure_behavior_summary: String,
235    pub pass_behavior_summary: String,
236    pub final_role: String,
237    pub final_motif: String,
238}
239
240#[derive(Debug, Clone, Serialize)]
241pub struct GroupValidationRow {
242    pub group_id: String,
243    pub group_members: String,
244    #[serde(rename = "failure co-activation count")]
245    pub failure_coactivation_count: usize,
246    #[serde(rename = "pass co-activation count")]
247    pub pass_coactivation_count: usize,
248    #[serde(rename = "retained_or_rejected")]
249    pub retained_or_rejected: String,
250    pub reason: String,
251}
252
253#[derive(Debug, Clone, Serialize)]
254pub struct HeuristicProvenanceRow {
255    pub heuristic_id: String,
256    pub derived_from_failures: String,
257    pub uses_features: String,
258    pub targets_nuisance_class: String,
259    pub intended_effect: String,
260    pub motif_signature: String,
261    pub allowed_grammar_states: String,
262    pub action: String,
263    pub constraints: String,
264    pub ambiguity_note: String,
265}
266
267#[derive(Debug, Clone, Serialize)]
268pub struct FeatureMotifGroundingRecord {
269    pub feature_index: usize,
270    pub feature_name: String,
271    pub motif_type: String,
272    pub dominant_dsfb_motif: String,
273    pub dominant_grammar_state: String,
274    pub failure_local_recovery_case_count: usize,
275    pub failure_window_semantic_hits: usize,
276    pub pass_run_semantic_hits: usize,
277    pub failure_window_pressure_hits: usize,
278    pub pass_run_pressure_hits: usize,
279    pub mean_abs_drift_failure: f64,
280    pub mean_abs_drift_pass: f64,
281    pub mean_abs_slew_failure: f64,
282    pub mean_abs_slew_pass: f64,
283    pub justification: String,
284}
285
286#[derive(Debug, Clone, Serialize)]
287pub struct MinimalHeuristicEntry {
288    pub heuristic_id: String,
289    pub target_problem_type: String,
290    pub target_identifier: String,
291    pub target_feature_name: Option<String>,
292    pub target_motif_type: String,
293    pub target_grammar_states: Vec<String>,
294    pub semantic_requirement: String,
295    pub policy_action: String,
296    pub burden_effect_class: String,
297    pub justification: String,
298    pub status: String,
299}
300
301#[derive(Debug, Clone, Serialize)]
302pub struct PolicyBurdenSummaryRow {
303    pub scope: String,
304    pub name: String,
305    pub watch_points: usize,
306    pub review_points: usize,
307    pub escalate_points: usize,
308    pub pass_review_escalate_points: usize,
309    pub pre_failure_review_escalate_points: usize,
310    pub silent_suppression_points: usize,
311    pub justification: String,
312}
313
314#[derive(Debug, Clone, Serialize)]
315pub struct DsfbVsEwmaCase {
316    pub failure_id: usize,
317    pub failure_timestamp: String,
318    pub recovered: bool,
319    pub recovered_feature_name: String,
320    pub baseline_miss_rule: String,
321    pub ewma_detected: bool,
322    pub ewma_lead_runs: Option<usize>,
323    pub optimized_dsa_lead_runs: Option<usize>,
324    pub explanation: String,
325    pub window: Vec<DsfbVsEwmaWindowPoint>,
326}
327
328#[derive(Debug, Clone, Serialize)]
329pub struct DsfbVsEwmaWindowPoint {
330    pub run_index: usize,
331    pub timestamp: String,
332    pub label: i8,
333    pub ewma_value: f64,
334    pub ewma_threshold: f64,
335    pub ewma_alarm: bool,
336    pub residual: f64,
337    pub drift: f64,
338    pub slew: f64,
339    pub motif_label: String,
340    pub grammar_state: String,
341    pub policy_state: String,
342}
343
344#[derive(Debug, Clone, Serialize)]
345pub struct FailureDrivenArtifacts {
346    pub failures_index: FailuresIndex,
347    pub missed_failure_priority: Vec<MissedFailurePriorityRow>,
348    pub failure_cases: Vec<FailureCaseReport>,
349    pub feature_motif_grounding: Vec<FeatureMotifGroundingRecord>,
350    pub feature_to_motif: Vec<FeatureToMotifRecord>,
351    pub negative_control_report: NegativeControlReport,
352    pub minimal_heuristics_bank: Vec<MinimalHeuristicEntry>,
353    pub heuristic_provenance: Vec<HeuristicProvenanceRow>,
354    pub policy_burden_summary: Vec<PolicyBurdenSummaryRow>,
355    pub feature_role_validation: Vec<FeatureRoleValidationRow>,
356    pub group_validation: Vec<GroupValidationRow>,
357    pub dsfb_vs_ewma_cases: Vec<DsfbVsEwmaCase>,
358}
359
360struct FeatureBundle<'a> {
361    residual: &'a ResidualFeatureTrace,
362    sign: &'a FeatureSigns,
363    grammar: &'a FeatureGrammarTrace,
364    motif: &'a FeatureMotifTrace,
365    ewma: &'a EwmaFeatureTrace,
366    baseline_dsa: &'a DsaFeatureTrace,
367    optimized_dsa: &'a DsaFeatureTrace,
368}
369
370#[derive(Debug, Clone)]
371struct FeatureActivityCandidate {
372    feature_index: usize,
373    feature_name: String,
374    ranking_score_proxy: f64,
375    max_dsa_score: f64,
376    max_policy_state: String,
377    motif_hits: usize,
378    pressure_hits: usize,
379}
380
381pub fn build_failure_driven_artifacts(
382    dataset: &PreparedDataset,
383    residuals: &ResidualSet,
384    signs: &SignSet,
385    baselines: &BaselineSet,
386    grammar: &GrammarSet,
387    motifs: &MotifSet,
388    semantic_layer: &SemanticLayer,
389    scaffold_semiotics: &ScaffoldSemioticsArtifacts,
390    metrics: &BenchmarkMetrics,
391    baseline_dsa: &DsaEvaluation,
392    optimized_dsa: &DsaEvaluation,
393    missed_failure_diagnostics: &[MissedFailureDiagnosticRow],
394    policy_operator_burden_contributions: &[OperatorBurdenContributionRow],
395    pre_failure_lookback_runs: usize,
396) -> FailureDrivenArtifacts {
397    let feature_bundles = index_feature_bundles(
398        residuals,
399        signs,
400        baselines,
401        grammar,
402        motifs,
403        baseline_dsa,
404        optimized_dsa,
405    );
406    let baseline_by_failure = baseline_dsa
407        .per_failure_run_signals
408        .iter()
409        .map(|row| (row.failure_run_index, row))
410        .collect::<BTreeMap<_, _>>();
411    let optimized_by_failure = optimized_dsa
412        .per_failure_run_signals
413        .iter()
414        .map(|row| (row.failure_run_index, row))
415        .collect::<BTreeMap<_, _>>();
416    let metrics_by_failure = metrics
417        .per_failure_run_signals
418        .iter()
419        .map(|row| (row.failure_run_index, row))
420        .collect::<BTreeMap<_, _>>();
421    let diagnostics_by_failure = missed_failure_diagnostics
422        .iter()
423        .map(|row| (row.failure_run_index, row))
424        .collect::<BTreeMap<_, _>>();
425
426    let failures_index = build_failures_index(
427        dataset,
428        &feature_bundles,
429        baseline_dsa,
430        optimized_dsa,
431        metrics,
432        pre_failure_lookback_runs,
433    );
434    let failure_cases = build_failure_cases(
435        dataset,
436        &feature_bundles,
437        semantic_layer,
438        &baseline_by_failure,
439        &optimized_by_failure,
440        &metrics_by_failure,
441        &diagnostics_by_failure,
442        pre_failure_lookback_runs,
443    );
444    let feature_motif_grounding = build_feature_motif_grounding(
445        dataset,
446        &feature_bundles,
447        semantic_layer,
448        baseline_dsa,
449        optimized_dsa,
450        missed_failure_diagnostics,
451        policy_operator_burden_contributions,
452        &failure_cases,
453        pre_failure_lookback_runs,
454    );
455    let missed_failure_priority =
456        build_missed_failure_priority(&failure_cases, &feature_motif_grounding);
457    let feature_to_motif = build_feature_to_motif(&failure_cases, &feature_motif_grounding);
458    let negative_control_report =
459        build_negative_control_report(dataset, optimized_dsa, pre_failure_lookback_runs);
460    let minimal_heuristics_bank = build_minimal_heuristics_bank(
461        missed_failure_diagnostics,
462        policy_operator_burden_contributions,
463        &feature_motif_grounding,
464    );
465    let heuristic_provenance = build_heuristic_provenance(&minimal_heuristics_bank);
466    let policy_burden_summary = build_policy_burden_summary(dataset, optimized_dsa);
467    let feature_role_validation = build_feature_role_validation(
468        dataset,
469        &feature_bundles,
470        semantic_layer,
471        &feature_motif_grounding,
472        &policy_burden_summary,
473        optimized_dsa,
474        missed_failure_diagnostics,
475        pre_failure_lookback_runs,
476    );
477    let group_validation = build_group_validation(&scaffold_semiotics.group_definitions);
478    let dsfb_vs_ewma_cases = build_dsfb_vs_ewma_cases(
479        dataset,
480        &feature_bundles,
481        &optimized_by_failure,
482        &metrics_by_failure,
483        &diagnostics_by_failure,
484        missed_failure_diagnostics,
485        pre_failure_lookback_runs,
486    );
487
488    let _ = scaffold_semiotics;
489
490    FailureDrivenArtifacts {
491        failures_index,
492        missed_failure_priority,
493        failure_cases,
494        feature_motif_grounding,
495        feature_to_motif,
496        negative_control_report,
497        minimal_heuristics_bank,
498        heuristic_provenance,
499        policy_burden_summary,
500        feature_role_validation,
501        group_validation,
502        dsfb_vs_ewma_cases,
503    }
504}
505
506pub fn validated_group_definitions(
507    definitions: &[GroupDefinitionRecord],
508) -> Vec<GroupDefinitionRecord> {
509    definitions
510        .iter()
511        .filter(|row| row.validated)
512        .cloned()
513        .collect()
514}
515
516pub fn grouped_semiotics_rejected(definitions: &[GroupDefinitionRecord]) -> bool {
517    definitions.iter().all(|row| !row.validated)
518}
519
520fn index_feature_bundles<'a>(
521    residuals: &'a ResidualSet,
522    signs: &'a SignSet,
523    baselines: &'a BaselineSet,
524    grammar: &'a GrammarSet,
525    motifs: &'a MotifSet,
526    baseline_dsa: &'a DsaEvaluation,
527    optimized_dsa: &'a DsaEvaluation,
528) -> BTreeMap<usize, FeatureBundle<'a>> {
529    let residual_by_feature = residuals
530        .traces
531        .iter()
532        .map(|row| (row.feature_index, row))
533        .collect::<BTreeMap<_, _>>();
534    let sign_by_feature = signs
535        .traces
536        .iter()
537        .map(|row| (row.feature_index, row))
538        .collect::<BTreeMap<_, _>>();
539    let grammar_by_feature = grammar
540        .traces
541        .iter()
542        .map(|row| (row.feature_index, row))
543        .collect::<BTreeMap<_, _>>();
544    let motif_by_feature = motifs
545        .traces
546        .iter()
547        .map(|row| (row.feature_index, row))
548        .collect::<BTreeMap<_, _>>();
549    let ewma_by_feature = baselines
550        .ewma
551        .iter()
552        .map(|row| (row.feature_index, row))
553        .collect::<BTreeMap<_, _>>();
554    let baseline_dsa_by_feature = baseline_dsa
555        .traces
556        .iter()
557        .map(|row| (row.feature_index, row))
558        .collect::<BTreeMap<_, _>>();
559    let optimized_dsa_by_feature = optimized_dsa
560        .traces
561        .iter()
562        .map(|row| (row.feature_index, row))
563        .collect::<BTreeMap<_, _>>();
564
565    residual_by_feature
566        .iter()
567        .filter_map(|(&feature_index, residual)| {
568            Some((
569                feature_index,
570                FeatureBundle {
571                    residual,
572                    sign: sign_by_feature.get(&feature_index)?,
573                    grammar: grammar_by_feature.get(&feature_index)?,
574                    motif: motif_by_feature.get(&feature_index)?,
575                    ewma: ewma_by_feature.get(&feature_index)?,
576                    baseline_dsa: baseline_dsa_by_feature.get(&feature_index)?,
577                    optimized_dsa: optimized_dsa_by_feature.get(&feature_index)?,
578                },
579            ))
580        })
581        .collect()
582}
583
584fn build_failures_index(
585    dataset: &PreparedDataset,
586    feature_bundles: &BTreeMap<usize, FeatureBundle<'_>>,
587    baseline_dsa: &DsaEvaluation,
588    optimized_dsa: &DsaEvaluation,
589    metrics: &BenchmarkMetrics,
590    pre_failure_lookback_runs: usize,
591) -> FailuresIndex {
592    let optimized_by_failure = optimized_dsa
593        .per_failure_run_signals
594        .iter()
595        .map(|row| (row.failure_run_index, row))
596        .collect::<BTreeMap<_, _>>();
597    let metrics_by_failure = metrics
598        .per_failure_run_signals
599        .iter()
600        .map(|row| (row.failure_run_index, row))
601        .collect::<BTreeMap<_, _>>();
602
603    let missed_failure_ids = baseline_dsa
604        .per_failure_run_signals
605        .iter()
606        .filter(|row| row.earliest_dsa_run.is_none())
607        .map(|row| row.failure_run_index)
608        .collect::<Vec<_>>();
609
610    let entries = baseline_dsa
611        .per_failure_run_signals
612        .iter()
613        .map(|row| {
614            let optimized = optimized_by_failure
615                .get(&row.failure_run_index)
616                .copied()
617                .unwrap_or(row);
618            let metric_row = metrics_by_failure
619                .get(&row.failure_run_index)
620                .copied()
621                .unwrap_or_else(|| {
622                    panic!(
623                        "missing metrics failure row for failure {}",
624                        row.failure_run_index
625                    )
626                });
627            let activity = top_feature_activity_for_failure(
628                feature_bundles,
629                row.failure_run_index,
630                pre_failure_lookback_runs,
631                MAX_FAILURE_INDEX_ACTIVITY,
632                true,
633            )
634            .into_iter()
635            .map(|candidate| FeatureActivitySummary {
636                feature_index: candidate.feature_index,
637                feature_name: candidate.feature_name,
638                max_dsa_score: candidate.max_dsa_score,
639                max_policy_state: candidate.max_policy_state,
640                motif_hits: candidate.motif_hits,
641                pressure_hits: candidate.pressure_hits,
642            })
643            .collect::<Vec<_>>();
644
645            FailureIndexEntry {
646                failure_id: row.failure_run_index,
647                timestamp_or_run_index: row.failure_timestamp.clone(),
648                timestamp: row.failure_timestamp.clone(),
649                detected_by_current_dsa: row.earliest_dsa_run.is_some(),
650                detected_by_dsa: row.earliest_dsa_run.is_some(),
651                detected_by_optimized_dsa: optimized.earliest_dsa_run.is_some(),
652                detected_by_ewma: metric_row.earliest_ewma_run.is_some(),
653                detected_by_threshold: metric_row.earliest_threshold_run.is_some(),
654                detected_by_cusum_if_present: metric_row.earliest_cusum_run.is_some(),
655                detected_by_run_energy_if_present: metric_row.earliest_run_energy_run.is_some(),
656                detected_by_pca_fdc_if_present: metric_row.earliest_pca_fdc_run.is_some(),
657                lead_time_dsa: row.dsa_lead_runs,
658                lead_time: row.dsa_lead_runs,
659                lead_time_threshold: metric_row.threshold_lead_runs,
660                lead_time_ewma: metric_row.ewma_lead_runs,
661                lead_time_cusum: metric_row.cusum_lead_runs,
662                lead_time_run_energy: metric_row.run_energy_lead_runs,
663                lead_time_pca_fdc: metric_row.pca_fdc_lead_runs,
664                optimized_lead_time: optimized.dsa_lead_runs,
665                feature_activity_summary: activity,
666            }
667        })
668        .collect::<Vec<_>>();
669
670    let _ = dataset;
671
672    FailuresIndex {
673        total_failure_count: baseline_dsa.per_failure_run_signals.len(),
674        missed_failure_ids,
675        entries,
676    }
677}
678
679fn build_failure_cases(
680    _dataset: &PreparedDataset,
681    feature_bundles: &BTreeMap<usize, FeatureBundle<'_>>,
682    semantic_layer: &SemanticLayer,
683    baseline_by_failure: &BTreeMap<usize, &PerFailureRunDsaSignal>,
684    optimized_by_failure: &BTreeMap<usize, &PerFailureRunDsaSignal>,
685    metrics_by_failure: &BTreeMap<usize, &PerFailureRunSignal>,
686    diagnostics_by_failure: &BTreeMap<usize, &MissedFailureDiagnosticRow>,
687    pre_failure_lookback_runs: usize,
688) -> Vec<FailureCaseReport> {
689    baseline_by_failure
690        .values()
691        .filter(|row| row.earliest_dsa_run.is_none())
692        .map(|baseline_row| {
693            let failure_index = baseline_row.failure_run_index;
694            let optimized_row = optimized_by_failure
695                .get(&failure_index)
696                .copied()
697                .unwrap_or(baseline_row);
698            let metrics_row = metrics_by_failure
699                .get(&failure_index)
700                .copied()
701                .unwrap_or_else(|| panic!("missing metrics case for failure {failure_index}"));
702            let diagnostic = diagnostics_by_failure.get(&failure_index).copied();
703            let start = failure_index.saturating_sub(pre_failure_lookback_runs);
704            let top_candidates = top_feature_activity_for_failure(
705                feature_bundles,
706                failure_index,
707                pre_failure_lookback_runs,
708                MAX_FAILURE_CASE_FEATURES,
709                false,
710            );
711
712            let top_contributing_features = top_candidates
713                .into_iter()
714                .map(|candidate| {
715                    let bundle = feature_bundles
716                        .get(&candidate.feature_index)
717                        .unwrap_or_else(|| {
718                            panic!("missing feature bundle {}", candidate.feature_index)
719                        });
720                    let semantic_labels = semantic_labels_in_window(
721                        semantic_layer,
722                        &candidate.feature_name,
723                        start,
724                        failure_index,
725                    );
726                    let dominant_dsfb_motif =
727                        dominant_motif_in_window(bundle.motif, start, failure_index);
728                    let dominant_grammar_state =
729                        dominant_grammar_state_in_window(bundle.grammar, start, failure_index);
730                    let initial_motif_hypothesis =
731                        grounded_motif_type_for_window(bundle, start, failure_index).to_string();
732                    let behavior_classification = classify_feature_behavior(
733                        &bundle.sign.drift[start..failure_index],
734                        &bundle.sign.slew[start..failure_index],
735                    )
736                    .to_string();
737                    let (failure_stage, failure_explanation) = feature_failure_explanation(
738                        bundle,
739                        start,
740                        failure_index,
741                        diagnostic,
742                        &semantic_labels,
743                    );
744
745                    FailureCaseFeatureDetail {
746                        feature_index: candidate.feature_index,
747                        feature_name: candidate.feature_name.clone(),
748                        behavior_classification: behavior_classification.clone(),
749                        initial_behavior_classification: behavior_classification,
750                        ranking_score_proxy: candidate.ranking_score_proxy,
751                        max_dsa_score: candidate.max_dsa_score,
752                        max_policy_state: candidate.max_policy_state,
753                        motif_hypothesis: initial_motif_hypothesis.clone(),
754                        initial_motif_hypothesis,
755                        dominant_dsfb_motif,
756                        dominant_grammar_state,
757                        semantic_labels,
758                        failure_stage,
759                        failure_explanation,
760                        residual_trajectory: bundle.residual.residuals[start..failure_index]
761                            .to_vec(),
762                        drift_trajectory: bundle.sign.drift[start..failure_index].to_vec(),
763                        slew_trajectory: bundle.sign.slew[start..failure_index].to_vec(),
764                        motif_timeline: bundle.motif.labels[start..failure_index]
765                            .iter()
766                            .map(|label| label.as_lowercase().to_string())
767                            .collect(),
768                        grammar_state_timeline: (start..failure_index)
769                            .map(|run_index| {
770                                failure_grammar_state_label(bundle.grammar, run_index).to_string()
771                            })
772                            .collect(),
773                        grammar_trajectory: (start..failure_index)
774                            .map(|run_index| {
775                                failure_grammar_state_label(bundle.grammar, run_index).to_string()
776                            })
777                            .collect(),
778                    }
779                })
780                .collect::<Vec<_>>();
781
782            let threshold_support = scalar_supporting_features(
783                feature_bundles,
784                start,
785                failure_index,
786                ScalarSupportMode::Threshold,
787            );
788            let ewma_support = scalar_supporting_features(
789                feature_bundles,
790                start,
791                failure_index,
792                ScalarSupportMode::Ewma,
793            );
794
795            FailureCaseReport {
796                failure_id: failure_index,
797                failure_timestamp: baseline_row.failure_timestamp.clone(),
798                baseline_detected_by_dsa: baseline_row.earliest_dsa_run.is_some(),
799                optimized_detected_by_dsa: optimized_row.earliest_dsa_run.is_some(),
800                detected_by_ewma: metrics_row.earliest_ewma_run.is_some(),
801                detected_by_threshold: metrics_row.earliest_threshold_run.is_some(),
802                baseline_dsa_lead_runs: baseline_row.dsa_lead_runs,
803                optimized_dsa_lead_runs: optimized_row.dsa_lead_runs,
804                ewma_lead_runs: metrics_row.ewma_lead_runs,
805                threshold_lead_runs: metrics_row.threshold_lead_runs,
806                exact_miss_rule: diagnostic
807                    .map(|row| row.exact_miss_rule.clone())
808                    .unwrap_or_else(|| "unclassified".into()),
809                failure_stage: failure_stage_label(diagnostic),
810                failure_explanation: failure_explanation_text(diagnostic, optimized_row),
811                ewma_detection_explanation: scalar_detection_explanation(
812                    "EWMA",
813                    metrics_row.earliest_ewma_run.is_some(),
814                    metrics_row.ewma_lead_runs,
815                    &ewma_support,
816                ),
817                threshold_detection_explanation: scalar_detection_explanation(
818                    "Threshold",
819                    metrics_row.earliest_threshold_run.is_some(),
820                    metrics_row.threshold_lead_runs,
821                    &threshold_support,
822                ),
823                why_dsfb_missed: failure_explanation_text(diagnostic, optimized_row),
824                missed_reason_class: miss_reason_class(diagnostic, optimized_row).into(),
825                why_ewma_succeeded_or_failed: scalar_detection_explanation(
826                    "EWMA",
827                    metrics_row.earliest_ewma_run.is_some(),
828                    metrics_row.ewma_lead_runs,
829                    &ewma_support,
830                ),
831                why_threshold_succeeded_or_failed: scalar_detection_explanation(
832                    "Threshold",
833                    metrics_row.earliest_threshold_run.is_some(),
834                    metrics_row.threshold_lead_runs,
835                    &threshold_support,
836                ),
837                top_contributing_features,
838            }
839        })
840        .collect()
841}
842
843fn build_feature_motif_grounding(
844    dataset: &PreparedDataset,
845    feature_bundles: &BTreeMap<usize, FeatureBundle<'_>>,
846    semantic_layer: &SemanticLayer,
847    baseline_dsa: &DsaEvaluation,
848    optimized_dsa: &DsaEvaluation,
849    missed_failure_diagnostics: &[MissedFailureDiagnosticRow],
850    policy_operator_burden_contributions: &[OperatorBurdenContributionRow],
851    failure_cases: &[FailureCaseReport],
852    pre_failure_lookback_runs: usize,
853) -> Vec<FeatureMotifGroundingRecord> {
854    let failure_indices = baseline_dsa
855        .per_failure_run_signals
856        .iter()
857        .map(|row| row.failure_run_index)
858        .collect::<Vec<_>>();
859    let failure_window_mask = build_failure_window_mask(
860        dataset.labels.len(),
861        &failure_indices,
862        pre_failure_lookback_runs,
863    );
864    let candidate_features = grounding_candidate_features(
865        baseline_dsa,
866        optimized_dsa,
867        missed_failure_diagnostics,
868        policy_operator_burden_contributions,
869        failure_cases,
870    );
871
872    candidate_features
873        .into_iter()
874        .filter_map(|feature_index| {
875            let bundle = feature_bundles.get(&feature_index)?;
876            let failure_semantic_hits = semantic_hit_count(
877                semantic_layer,
878                &bundle.residual.feature_name,
879                &failure_window_mask,
880                true,
881            );
882            let pass_semantic_hits = semantic_hit_count(
883                semantic_layer,
884                &bundle.residual.feature_name,
885                &failure_window_mask,
886                false,
887            );
888            let failure_pressure_hits = pressure_hit_count(bundle.grammar, &failure_window_mask, true);
889            let pass_pressure_hits = pressure_hit_count(bundle.grammar, &failure_window_mask, false);
890            let mean_abs_drift_failure =
891                masked_mean_abs(&bundle.sign.drift, &failure_window_mask, true);
892            let mean_abs_drift_pass = masked_mean_abs(&bundle.sign.drift, &failure_window_mask, false);
893            let mean_abs_slew_failure =
894                masked_mean_abs(&bundle.sign.slew, &failure_window_mask, true);
895            let mean_abs_slew_pass = masked_mean_abs(&bundle.sign.slew, &failure_window_mask, false);
896            let dominant_dsfb_motif = dominant_motif_for_mask(bundle.motif, &failure_window_mask, true);
897            let dominant_grammar_state =
898                dominant_grammar_state_for_mask(bundle.grammar, &failure_window_mask, true);
899            let failure_local_recovery_case_count = failure_cases
900                .iter()
901                .flat_map(|case| case.top_contributing_features.iter())
902                .filter(|feature| {
903                    feature.feature_index == feature_index
904                        && feature.initial_motif_hypothesis == "recovery_pattern"
905                        && feature.dominant_grammar_state == "Recovery"
906                })
907                .count();
908            let motif_type = grounded_motif_type(
909                dominant_dsfb_motif.as_str(),
910                dominant_grammar_state.as_str(),
911                failure_local_recovery_case_count,
912                failure_semantic_hits,
913                pass_semantic_hits,
914                failure_pressure_hits,
915                pass_pressure_hits,
916                mean_abs_drift_failure,
917                mean_abs_slew_failure,
918            );
919
920            Some(FeatureMotifGroundingRecord {
921                feature_index,
922                feature_name: bundle.residual.feature_name.clone(),
923                motif_type: motif_type.to_string(),
924                dominant_dsfb_motif,
925                dominant_grammar_state,
926                failure_local_recovery_case_count,
927                failure_window_semantic_hits: failure_semantic_hits,
928                pass_run_semantic_hits: pass_semantic_hits,
929                failure_window_pressure_hits: failure_pressure_hits,
930                pass_run_pressure_hits: pass_pressure_hits,
931                mean_abs_drift_failure,
932                mean_abs_drift_pass,
933                mean_abs_slew_failure,
934                mean_abs_slew_pass,
935                justification: format!(
936                    "Failure-window semantic hits={}, pass-run semantic hits={}, failure pressure hits={}, pass pressure hits={}, failure-local recovery cases={}, |drift|_failure={:.4}, |slew|_failure={:.4}.",
937                    failure_semantic_hits,
938                    pass_semantic_hits,
939                    failure_pressure_hits,
940                    pass_pressure_hits,
941                    failure_local_recovery_case_count,
942                    mean_abs_drift_failure,
943                    mean_abs_slew_failure,
944                ),
945            })
946        })
947        .collect()
948}
949
950fn build_missed_failure_priority(
951    failure_cases: &[FailureCaseReport],
952    feature_motif_grounding: &[FeatureMotifGroundingRecord],
953) -> Vec<MissedFailurePriorityRow> {
954    let grounding_by_name = feature_motif_grounding
955        .iter()
956        .map(|row| (row.feature_name.as_str(), row))
957        .collect::<BTreeMap<_, _>>();
958    let mut rows = failure_cases
959        .iter()
960        .map(|case| {
961            let signal_strength = case
962                .top_contributing_features
963                .iter()
964                .map(|feature| feature.max_dsa_score)
965                .fold(0.0, f64::max);
966            let total_proxy = case
967                .top_contributing_features
968                .iter()
969                .map(|feature| feature.ranking_score_proxy)
970                .sum::<f64>();
971            let feature_concentration = case
972                .top_contributing_features
973                .first()
974                .map(|feature| feature.ranking_score_proxy / total_proxy.max(1.0e-9))
975                .unwrap_or(0.0);
976            let top_feature_name = case
977                .top_contributing_features
978                .first()
979                .map(|feature| feature.feature_name.clone());
980            let separation_from_noise = top_feature_name
981                .as_deref()
982                .and_then(|feature_name| grounding_by_name.get(feature_name))
983                .map(|row| {
984                    (row.failure_window_semantic_hits as f64
985                        + row.failure_window_pressure_hits as f64)
986                        / (1.0
987                            + row.pass_run_semantic_hits as f64
988                            + row.pass_run_pressure_hits as f64)
989                })
990                .unwrap_or(0.0);
991            let recoverability_estimate = if case.optimized_detected_by_dsa {
992                1.0
993            } else {
994                0.0
995            };
996            let priority_score = signal_strength
997                + feature_concentration
998                + separation_from_noise
999                + recoverability_estimate;
1000            MissedFailurePriorityRow {
1001                failure_id: case.failure_id,
1002                timestamp: case.failure_timestamp.clone(),
1003                exact_miss_rule: case.exact_miss_rule.clone(),
1004                top_feature_name,
1005                signal_strength,
1006                feature_concentration,
1007                separation_from_noise,
1008                recoverability_estimate,
1009                priority_score,
1010            }
1011        })
1012        .collect::<Vec<_>>();
1013    rows.sort_by(|left, right| {
1014        right
1015            .priority_score
1016            .partial_cmp(&left.priority_score)
1017            .unwrap_or(std::cmp::Ordering::Equal)
1018            .then_with(|| left.failure_id.cmp(&right.failure_id))
1019    });
1020    rows
1021}
1022
1023fn build_feature_to_motif(
1024    failure_cases: &[FailureCaseReport],
1025    feature_motif_grounding: &[FeatureMotifGroundingRecord],
1026) -> Vec<FeatureToMotifRecord> {
1027    let mut counts = BTreeMap::<usize, usize>::new();
1028    for case in failure_cases {
1029        for feature in &case.top_contributing_features {
1030            *counts.entry(feature.feature_index).or_default() += 1;
1031        }
1032    }
1033    let grounding_by_index = feature_motif_grounding
1034        .iter()
1035        .map(|row| (row.feature_index, row))
1036        .collect::<BTreeMap<_, _>>();
1037    let mut selected = counts.into_iter().collect::<Vec<_>>();
1038    selected.sort_by(|left, right| right.1.cmp(&left.1).then_with(|| left.0.cmp(&right.0)));
1039    let mut ordered_feature_indices = Vec::new();
1040    let mut seen = BTreeSet::new();
1041
1042    for spec in FEATURE_ROLE_LOCK {
1043        if let Some(feature_index) = feature_index_from_name(spec.feature_name) {
1044            if seen.insert(feature_index) {
1045                ordered_feature_indices.push(feature_index);
1046            }
1047        }
1048    }
1049    for (feature_index, _) in selected {
1050        if ordered_feature_indices.len() >= 15 {
1051            break;
1052        }
1053        if seen.insert(feature_index) {
1054            ordered_feature_indices.push(feature_index);
1055        }
1056    }
1057
1058    ordered_feature_indices
1059        .into_iter()
1060        .filter_map(|feature_index| {
1061            let grounding = grounding_by_index.get(&feature_index)?;
1062            let initial_role = FEATURE_ROLE_LOCK
1063                .iter()
1064                .find(|spec| spec.feature_name == grounding.feature_name)
1065                .map(|spec| spec.initial_role)
1066                .unwrap_or("failure-ranked candidate feature");
1067            Some(FeatureToMotifRecord {
1068                feature_index,
1069                feature_name: grounding.feature_name.clone(),
1070                initial_role: initial_role.into(),
1071                motif_type: grounding.motif_type.clone(),
1072                failure_behavior_justification: format!(
1073                    "failure semantic hits={}, failure pressure hits={}, dominant failure motif={}, dominant failure grammar={}",
1074                    grounding.failure_window_semantic_hits,
1075                    grounding.failure_window_pressure_hits,
1076                    grounding.dominant_dsfb_motif,
1077                    grounding.dominant_grammar_state,
1078                ),
1079                pass_behavior_justification: format!(
1080                    "pass semantic hits={}, pass pressure hits={}, |drift|_pass={:.4}, |slew|_pass={:.4}",
1081                    grounding.pass_run_semantic_hits,
1082                    grounding.pass_run_pressure_hits,
1083                    grounding.mean_abs_drift_pass,
1084                    grounding.mean_abs_slew_pass,
1085                ),
1086                justification: grounding.justification.clone(),
1087            })
1088        })
1089        .collect()
1090}
1091
1092fn build_negative_control_report(
1093    dataset: &PreparedDataset,
1094    optimized_dsa: &DsaEvaluation,
1095    pre_failure_lookback_runs: usize,
1096) -> NegativeControlReport {
1097    let failure_indices = dataset
1098        .labels
1099        .iter()
1100        .enumerate()
1101        .filter_map(|(run_index, label)| (*label == 1).then_some(run_index))
1102        .collect::<Vec<_>>();
1103    let failure_window_mask = build_failure_window_mask(
1104        dataset.labels.len(),
1105        &failure_indices,
1106        pre_failure_lookback_runs,
1107    );
1108    let pass_run_count = dataset.labels.iter().filter(|label| **label == -1).count();
1109    let pass_run_false_activation_count = optimized_dsa
1110        .run_signals
1111        .primary_run_alert
1112        .iter()
1113        .enumerate()
1114        .filter(|(run_index, flag)| dataset.labels[*run_index] == -1 && **flag)
1115        .count();
1116    let pass_only_signal = optimized_dsa
1117        .run_signals
1118        .primary_run_alert
1119        .iter()
1120        .enumerate()
1121        .map(|(run_index, flag)| dataset.labels[run_index] == -1 && *flag)
1122        .collect::<Vec<_>>();
1123    let clean_window_mask = dataset
1124        .labels
1125        .iter()
1126        .enumerate()
1127        .map(|(run_index, label)| *label == -1 && !failure_window_mask[run_index])
1128        .collect::<Vec<_>>();
1129    let clean_window_count = clean_window_mask.iter().filter(|flag| **flag).count();
1130    let clean_window_false_activation_count = optimized_dsa
1131        .run_signals
1132        .primary_run_alert
1133        .iter()
1134        .enumerate()
1135        .filter(|(run_index, flag)| clean_window_mask[*run_index] && **flag)
1136        .count();
1137    let clean_window_signal = optimized_dsa
1138        .run_signals
1139        .primary_run_alert
1140        .iter()
1141        .enumerate()
1142        .map(|(run_index, flag)| clean_window_mask[run_index] && *flag)
1143        .collect::<Vec<_>>();
1144
1145    NegativeControlReport {
1146        pass_run_count,
1147        pass_run_false_activation_count,
1148        false_activation_rate: pass_run_false_activation_count as f64
1149            / pass_run_count.max(1) as f64,
1150        pass_run_false_episode_count: episode_ranges(&pass_only_signal).len(),
1151        false_episode_rate: episode_ranges(&pass_only_signal).len() as f64
1152            / pass_run_count.max(1) as f64,
1153        review_escalate_points_on_pass_runs: pass_run_false_activation_count,
1154        review_escalate_episodes_on_pass_runs: episode_ranges(&pass_only_signal).len(),
1155        clean_window_count,
1156        clean_window_false_activation_count,
1157        clean_window_false_activation_rate: clean_window_false_activation_count as f64
1158            / clean_window_count.max(1) as f64,
1159        clean_window_false_episode_count: episode_ranges(&clean_window_signal).len(),
1160        clean_window_false_episode_rate: episode_ranges(&clean_window_signal).len() as f64
1161            / clean_window_count.max(1) as f64,
1162        review_escalate_points_on_clean_runs: clean_window_false_activation_count,
1163        review_escalate_episodes_on_clean_runs: episode_ranges(&clean_window_signal).len(),
1164    }
1165}
1166
1167fn build_heuristic_provenance(
1168    minimal_heuristics_bank: &[MinimalHeuristicEntry],
1169) -> Vec<HeuristicProvenanceRow> {
1170    minimal_heuristics_bank
1171        .iter()
1172        .map(|entry| {
1173            let derived_from_failures = if entry.target_problem_type == "missed_failure" {
1174                bracketed_csv_list(&[entry.target_identifier.clone()])
1175            } else {
1176                "[]".into()
1177            };
1178            let uses_features = entry
1179                .target_feature_name
1180                .as_ref()
1181                .map(|feature_name| bracketed_csv_list(std::slice::from_ref(feature_name)))
1182                .unwrap_or_else(|| "[]".into());
1183            let targets_nuisance_class = if entry.target_problem_type == "nuisance_class" {
1184                entry.target_identifier.clone()
1185            } else {
1186                String::new()
1187            };
1188            let intended_effect = if entry.target_problem_type == "missed_failure" {
1189                "recover_failure"
1190            } else {
1191                "suppress_burden"
1192            };
1193            HeuristicProvenanceRow {
1194                heuristic_id: entry.heuristic_id.clone(),
1195                derived_from_failures,
1196                uses_features,
1197                targets_nuisance_class,
1198                intended_effect: intended_effect.into(),
1199                motif_signature: entry.target_motif_type.clone(),
1200                allowed_grammar_states: entry.target_grammar_states.join("|"),
1201                action: entry.policy_action.clone(),
1202                constraints: format!(
1203                    "semantic_requirement={}, status={}, burden_effect_class={}",
1204                    entry.semantic_requirement, entry.status, entry.burden_effect_class
1205                ),
1206                ambiguity_note:
1207                    "heuristic remains bounded to one failure or nuisance class and does not imply mechanism identity"
1208                        .into(),
1209            }
1210        })
1211        .collect()
1212}
1213
1214fn build_feature_role_validation(
1215    dataset: &PreparedDataset,
1216    feature_bundles: &BTreeMap<usize, FeatureBundle<'_>>,
1217    semantic_layer: &SemanticLayer,
1218    feature_motif_grounding: &[FeatureMotifGroundingRecord],
1219    policy_burden_summary: &[PolicyBurdenSummaryRow],
1220    optimized_dsa: &DsaEvaluation,
1221    missed_failure_diagnostics: &[MissedFailureDiagnosticRow],
1222    pre_failure_lookback_runs: usize,
1223) -> Vec<FeatureRoleValidationRow> {
1224    let failure_indices = optimized_dsa
1225        .per_failure_run_signals
1226        .iter()
1227        .map(|row| row.failure_run_index)
1228        .collect::<Vec<_>>();
1229    let failure_window_mask = build_failure_window_mask(
1230        dataset.labels.len(),
1231        &failure_indices,
1232        pre_failure_lookback_runs,
1233    );
1234    let grounding_by_name = feature_motif_grounding
1235        .iter()
1236        .map(|row| (row.feature_name.as_str(), row))
1237        .collect::<BTreeMap<_, _>>();
1238    let burden_by_name = policy_burden_summary
1239        .iter()
1240        .filter(|row| row.scope == "feature")
1241        .map(|row| (row.name.as_str(), row))
1242        .collect::<BTreeMap<_, _>>();
1243    let earliest_counts = optimized_dsa
1244        .per_failure_run_signals
1245        .iter()
1246        .filter_map(|row| row.earliest_dsa_feature_name.as_deref())
1247        .fold(BTreeMap::<&str, usize>::new(), |mut acc, feature_name| {
1248            *acc.entry(feature_name).or_default() += 1;
1249            acc
1250        });
1251    let max_score_counts = optimized_dsa
1252        .per_failure_run_signals
1253        .iter()
1254        .filter_map(|row| row.max_dsa_score_feature_name.as_deref())
1255        .fold(BTreeMap::<&str, usize>::new(), |mut acc, feature_name| {
1256            *acc.entry(feature_name).or_default() += 1;
1257            acc
1258        });
1259    let direct_miss_counts = missed_failure_diagnostics
1260        .iter()
1261        .filter_map(|row| row.nearest_feature_name.as_deref())
1262        .fold(BTreeMap::<&str, usize>::new(), |mut acc, feature_name| {
1263            *acc.entry(feature_name).or_default() += 1;
1264            acc
1265        });
1266    let optimized_target_counts = missed_failure_diagnostics
1267        .iter()
1268        .filter_map(|row| row.optimized_feature_name.as_deref())
1269        .fold(BTreeMap::<&str, usize>::new(), |mut acc, feature_name| {
1270            *acc.entry(feature_name).or_default() += 1;
1271            acc
1272        });
1273    let recovered_by_name = missed_failure_diagnostics
1274        .iter()
1275        .filter(|row| row.recovered_after_optimization)
1276        .filter_map(|row| row.optimized_feature_name.as_deref())
1277        .fold(BTreeMap::<&str, usize>::new(), |mut acc, feature_name| {
1278            *acc.entry(feature_name).or_default() += 1;
1279            acc
1280        });
1281
1282    FEATURE_ROLE_LOCK
1283        .iter()
1284        .map(|spec| {
1285            let feature_name = spec.feature_name;
1286            let grounding = grounding_by_name.get(feature_name).copied();
1287            let burden = burden_by_name.get(feature_name).copied();
1288            let bundle = feature_index_from_name(feature_name)
1289                .and_then(|feature_index| feature_bundles.get(&feature_index));
1290            let earliest_count = earliest_counts.get(feature_name).copied().unwrap_or(0);
1291            let max_score_count = max_score_counts.get(feature_name).copied().unwrap_or(0);
1292            let direct_miss_count = direct_miss_counts.get(feature_name).copied().unwrap_or(0);
1293            let optimized_target_count = optimized_target_counts.get(feature_name).copied().unwrap_or(0);
1294            let recovered_count = recovered_by_name.get(feature_name).copied().unwrap_or(0);
1295            let pass_burden = burden
1296                .map(|row| row.pass_review_escalate_points)
1297                .unwrap_or(0);
1298            let linked_failure_ids = linked_failure_ids_for_feature(
1299                feature_name,
1300                optimized_dsa,
1301                missed_failure_diagnostics,
1302            );
1303            let preferred_failure_semantic_hits = preferred_semantic_hit_count(
1304                semantic_layer,
1305                feature_name,
1306                &failure_window_mask,
1307                true,
1308                spec.preferred_semantic_labels,
1309            );
1310            let preferred_pass_semantic_hits = preferred_semantic_hit_count(
1311                semantic_layer,
1312                feature_name,
1313                &failure_window_mask,
1314                false,
1315                spec.preferred_semantic_labels,
1316            );
1317            let preferred_failure_grammar_hits = bundle
1318                .map(|bundle| {
1319                    preferred_grammar_hit_count(
1320                        bundle.grammar,
1321                        &failure_window_mask,
1322                        true,
1323                        spec.preferred_grammar_states,
1324                    )
1325                })
1326                .unwrap_or(0);
1327            let preferred_pass_grammar_hits = bundle
1328                .map(|bundle| {
1329                    preferred_grammar_hit_count(
1330                        bundle.grammar,
1331                        &failure_window_mask,
1332                        false,
1333                        spec.preferred_grammar_states,
1334                    )
1335                })
1336                .unwrap_or(0);
1337            let (linked_groundings, preferred_grounded_windows) = bundle
1338                .map(|bundle| {
1339                    linked_window_grounding_counts(
1340                        bundle,
1341                        &linked_failure_ids,
1342                        pre_failure_lookback_runs,
1343                        spec.preferred_grounded_motif_types,
1344                    )
1345                })
1346                .unwrap_or_default();
1347            let (linked_grammar, preferred_grammar_windows) = bundle
1348                .map(|bundle| {
1349                    linked_window_grammar_counts(
1350                        bundle.grammar,
1351                        &linked_failure_ids,
1352                        pre_failure_lookback_runs,
1353                        spec.preferred_grammar_states,
1354                    )
1355                })
1356                .unwrap_or_default();
1357
1358            let structural_support = preferred_grounded_windows > 0
1359                || preferred_grammar_windows > 0
1360                || (preferred_failure_semantic_hits > 0
1361                    && preferred_failure_semantic_hits >= preferred_pass_semantic_hits);
1362            let operational_failure_link = earliest_count + max_score_count + direct_miss_count + optimized_target_count;
1363            let (validation_result, final_role) = match feature_name {
1364                "S059" => {
1365                    if structural_support && operational_failure_link > 0 {
1366                        ("supported", spec.initial_role)
1367                    } else if operational_failure_link > 0 {
1368                        (
1369                            "revised",
1370                            spec.revised_role.unwrap_or(spec.initial_role),
1371                        )
1372                    } else if pass_burden > 0 {
1373                        (
1374                            "rejected",
1375                            "high-burden recurrent-boundary candidate without failure-local support",
1376                        )
1377                    } else {
1378                        ("revised", spec.revised_role.unwrap_or(spec.initial_role))
1379                    }
1380                }
1381                "S123" => {
1382                    if structural_support && (earliest_count > 0 || max_score_count > 0) {
1383                        ("supported", spec.initial_role)
1384                    } else if operational_failure_link > 0 {
1385                        (
1386                            "revised",
1387                            spec.revised_role.unwrap_or(spec.initial_role),
1388                        )
1389                    } else {
1390                        ("rejected", "transition / instability feature without failure-local support")
1391                    }
1392                }
1393                "S133" => {
1394                    if structural_support
1395                        && preferred_failure_semantic_hits > preferred_pass_semantic_hits
1396                        && preferred_grammar_windows > 0
1397                    {
1398                        ("supported", spec.initial_role)
1399                    } else {
1400                        (
1401                            "revised",
1402                            spec.revised_role.unwrap_or(spec.initial_role),
1403                        )
1404                    }
1405                }
1406                "S540" | "S128" => {
1407                    if structural_support && max_score_count > 0 {
1408                        ("supported", spec.initial_role)
1409                    } else if operational_failure_link > 0 {
1410                        (
1411                            "revised",
1412                            spec.revised_role.unwrap_or(spec.initial_role),
1413                        )
1414                    } else {
1415                        ("rejected", "corroborator remained failure-unlinked")
1416                    }
1417                }
1418                "S104" => {
1419                    let sentinel_supported = grounding.is_some_and(|row| {
1420                        matches!(row.motif_type.as_str(), "boundary_grazing" | "noise_like")
1421                    }) && pass_burden == 0
1422                        && earliest_count == 0
1423                        && recovered_count == 0;
1424                    if sentinel_supported {
1425                        ("supported", spec.initial_role)
1426                    } else {
1427                        (
1428                            "revised",
1429                            spec.revised_role.unwrap_or(spec.initial_role),
1430                        )
1431                    }
1432                }
1433                "S134" | "S275" => {
1434                    if direct_miss_count > 0 || optimized_target_count > 0 || recovered_count > 0 {
1435                        (
1436                            "supported",
1437                            spec.revised_role.unwrap_or(spec.initial_role),
1438                        )
1439                    } else {
1440                        ("rejected", "unlinked recall-rescue feature")
1441                    }
1442                }
1443                _ => ("supported", spec.initial_role),
1444            };
1445
1446            FeatureRoleValidationRow {
1447                feature_id: feature_name.into(),
1448                initial_role: spec.initial_role.into(),
1449                initial_motif: spec
1450                    .preferred_grounded_motif_types
1451                    .first()
1452                    .copied()
1453                    .unwrap_or("null")
1454                    .into(),
1455                supported_or_revised_or_rejected: validation_result.into(),
1456                failure_behavior_summary: format!(
1457                    "preferred semantic hits failure/pass={}/{}, preferred grammar hits failure/pass={}/{}, linked failure windows={}, linked grounded motifs={}, linked dominant grammar={}, earliest detection count={}, max-score failure count={}, direct miss linkages={}, optimized rescue targets={}, recovered missed failures={}, linked failures={}",
1458                    preferred_failure_semantic_hits,
1459                    preferred_pass_semantic_hits,
1460                    preferred_failure_grammar_hits,
1461                    preferred_pass_grammar_hits,
1462                    linked_failure_ids.len(),
1463                    summarize_count_map(&linked_groundings),
1464                    summarize_count_map(&linked_grammar),
1465                    earliest_count,
1466                    max_score_count,
1467                    direct_miss_count,
1468                    optimized_target_count,
1469                    recovered_count,
1470                    bracketed_usize_list(&linked_failure_ids),
1471                ),
1472                pass_behavior_summary: burden
1473                    .map(|row| {
1474                        format!(
1475                            "pass review/escalate points={}, silent suppressions={}, preferred semantic pass hits={}, preferred grammar pass hits={}, dominant pass grounding={}",
1476                            row.pass_review_escalate_points,
1477                            row.silent_suppression_points,
1478                            preferred_pass_semantic_hits,
1479                            preferred_pass_grammar_hits,
1480                            grounding
1481                                .map(|grounding| format!(
1482                                    "{} via {}",
1483                                    grounding.motif_type, grounding.dominant_dsfb_motif
1484                                ))
1485                                .unwrap_or_else(|| "none".into()),
1486                        )
1487                    })
1488                    .unwrap_or_else(|| {
1489                        format!(
1490                            "no pass-run burden, preferred semantic pass hits={}, preferred grammar pass hits={}, dominant pass grounding={}",
1491                            preferred_pass_semantic_hits,
1492                            preferred_pass_grammar_hits,
1493                            grounding
1494                                .map(|grounding| format!(
1495                                    "{} via {}",
1496                                    grounding.motif_type, grounding.dominant_dsfb_motif
1497                                ))
1498                                .unwrap_or_else(|| "none".into()),
1499                        )
1500                    }),
1501                final_role: final_role.into(),
1502                final_motif: grounding
1503                    .map(|row| row.motif_type.clone())
1504                    .unwrap_or_else(|| "null".into()),
1505            }
1506        })
1507        .collect()
1508}
1509
1510fn build_group_validation(definitions: &[GroupDefinitionRecord]) -> Vec<GroupValidationRow> {
1511    definitions
1512        .iter()
1513        .map(|row| GroupValidationRow {
1514            group_id: group_display_name(&row.group_name).into(),
1515            group_members: row.member_features.clone(),
1516            failure_coactivation_count: row.failure_coactivation_run_count,
1517            pass_coactivation_count: row.pass_coactivation_run_count,
1518            retained_or_rejected: if row.validated {
1519                "retained".into()
1520            } else {
1521                "rejected".into()
1522            },
1523            reason: row
1524                .rejection_reason
1525                .clone()
1526                .unwrap_or_else(|| "validated by empirical failure-vs-pass gate".into()),
1527        })
1528        .collect()
1529}
1530
1531fn linked_failure_ids_for_feature(
1532    feature_name: &str,
1533    optimized_dsa: &DsaEvaluation,
1534    missed_failure_diagnostics: &[MissedFailureDiagnosticRow],
1535) -> Vec<usize> {
1536    let mut linked = BTreeSet::new();
1537    for row in &optimized_dsa.per_failure_run_signals {
1538        if row.earliest_dsa_feature_name.as_deref() == Some(feature_name)
1539            || row.max_dsa_score_feature_name.as_deref() == Some(feature_name)
1540        {
1541            linked.insert(row.failure_run_index);
1542        }
1543    }
1544    for row in missed_failure_diagnostics {
1545        if row.nearest_feature_name.as_deref() == Some(feature_name)
1546            || row.optimized_feature_name.as_deref() == Some(feature_name)
1547        {
1548            linked.insert(row.failure_run_index);
1549        }
1550    }
1551    linked.into_iter().collect()
1552}
1553
1554fn preferred_semantic_hit_count(
1555    semantic_layer: &SemanticLayer,
1556    feature_name: &str,
1557    failure_window_mask: &[bool],
1558    in_failure_window: bool,
1559    preferred_labels: &[&str],
1560) -> usize {
1561    if preferred_labels.is_empty() {
1562        return 0;
1563    }
1564    semantic_layer
1565        .semantic_matches
1566        .iter()
1567        .filter(|row| row.feature_name == feature_name)
1568        .filter(|row| failure_window_mask[row.run_index] == in_failure_window)
1569        .filter(|row| preferred_labels.contains(&row.heuristic_name.as_str()))
1570        .count()
1571}
1572
1573fn preferred_grammar_hit_count(
1574    grammar_trace: &FeatureGrammarTrace,
1575    failure_window_mask: &[bool],
1576    in_failure_window: bool,
1577    preferred_states: &[&str],
1578) -> usize {
1579    if preferred_states.is_empty() {
1580        return 0;
1581    }
1582    grammar_trace
1583        .raw_states
1584        .iter()
1585        .enumerate()
1586        .filter(|(run_index, _)| failure_window_mask[*run_index] == in_failure_window)
1587        .filter(|(run_index, _)| {
1588            preferred_states.contains(&failure_grammar_state_label(grammar_trace, *run_index))
1589        })
1590        .count()
1591}
1592
1593fn linked_window_grounding_counts(
1594    bundle: &FeatureBundle<'_>,
1595    linked_failure_ids: &[usize],
1596    pre_failure_lookback_runs: usize,
1597    preferred_grounded_motif_types: &[&str],
1598) -> (BTreeMap<String, usize>, usize) {
1599    let mut counts = BTreeMap::<String, usize>::new();
1600    let mut preferred_window_count = 0usize;
1601    for &failure_index in linked_failure_ids {
1602        let start = failure_index.saturating_sub(pre_failure_lookback_runs);
1603        let grounded = grounded_motif_type_for_window(bundle, start, failure_index).to_string();
1604        if preferred_grounded_motif_types.contains(&grounded.as_str()) {
1605            preferred_window_count += 1;
1606        }
1607        *counts.entry(grounded).or_default() += 1;
1608    }
1609    (counts, preferred_window_count)
1610}
1611
1612fn linked_window_grammar_counts(
1613    grammar_trace: &FeatureGrammarTrace,
1614    linked_failure_ids: &[usize],
1615    pre_failure_lookback_runs: usize,
1616    preferred_grammar_states: &[&str],
1617) -> (BTreeMap<String, usize>, usize) {
1618    let mut counts = BTreeMap::<String, usize>::new();
1619    let mut preferred_window_count = 0usize;
1620    for &failure_index in linked_failure_ids {
1621        let start = failure_index.saturating_sub(pre_failure_lookback_runs);
1622        let dominant = dominant_grammar_state_in_window(grammar_trace, start, failure_index);
1623        if preferred_grammar_states.contains(&dominant.as_str()) {
1624            preferred_window_count += 1;
1625        }
1626        *counts.entry(dominant).or_default() += 1;
1627    }
1628    (counts, preferred_window_count)
1629}
1630
1631fn summarize_count_map(counts: &BTreeMap<String, usize>) -> String {
1632    if counts.is_empty() {
1633        "none".into()
1634    } else {
1635        counts
1636            .iter()
1637            .map(|(label, count)| format!("{label}:{count}"))
1638            .collect::<Vec<_>>()
1639            .join(";")
1640    }
1641}
1642
1643fn bracketed_csv_list(values: &[String]) -> String {
1644    if values.is_empty() {
1645        "[]".into()
1646    } else {
1647        format!("[{}]", values.join(","))
1648    }
1649}
1650
1651fn bracketed_usize_list(values: &[usize]) -> String {
1652    let items = values
1653        .iter()
1654        .map(|value| value.to_string())
1655        .collect::<Vec<_>>();
1656    bracketed_csv_list(&items)
1657}
1658
1659fn group_display_name(group_name: &str) -> &'static str {
1660    match group_name {
1661        "group_a" => "Group A",
1662        "group_b" => "Group B",
1663        "group_c" => "Group C",
1664        _ => "Unknown Group",
1665    }
1666}
1667
1668fn classify_feature_behavior(drift: &[f64], slew: &[f64]) -> &'static str {
1669    let mean_abs_drift = mean_abs(drift);
1670    let mean_abs_slew = mean_abs(slew);
1671    if mean_abs_drift < 0.02 && mean_abs_slew < 0.02 {
1672        "noise-like"
1673    } else if mean_abs_drift < 0.05 && mean_abs_slew < 0.05 {
1674        "stable"
1675    } else if mean_abs_slew > mean_abs_drift * 1.5 {
1676        "bursty"
1677    } else if drift.iter().any(|value| *value > 0.0) && drift.iter().any(|value| *value < 0.0) {
1678        "oscillatory"
1679    } else {
1680        "drifting"
1681    }
1682}
1683
1684fn build_minimal_heuristics_bank(
1685    missed_failure_diagnostics: &[MissedFailureDiagnosticRow],
1686    policy_operator_burden_contributions: &[OperatorBurdenContributionRow],
1687    feature_motif_grounding: &[FeatureMotifGroundingRecord],
1688) -> Vec<MinimalHeuristicEntry> {
1689    let grounding_by_name = feature_motif_grounding
1690        .iter()
1691        .map(|row| (row.feature_name.as_str(), row))
1692        .collect::<BTreeMap<_, _>>();
1693    let mut entries = Vec::new();
1694
1695    for diagnostic in missed_failure_diagnostics {
1696        let feature_name = match diagnostic.nearest_feature_name.as_deref() {
1697            Some("S134" | "S275") => diagnostic.nearest_feature_name.clone(),
1698            _ => diagnostic
1699                .optimized_feature_name
1700                .clone()
1701                .or_else(|| diagnostic.nearest_feature_name.clone()),
1702        };
1703        let motif_type = feature_name
1704            .as_deref()
1705            .and_then(|name| grounding_by_name.get(name).copied())
1706            .map(|row| row.motif_type.clone())
1707            .unwrap_or_else(|| "null".into());
1708        let (target_grammar_states, policy_action, status, burden_effect_class) =
1709            match diagnostic.exact_miss_rule.as_str() {
1710                "directional_consistency_gate" => (
1711                    vec!["BoundaryGrazing".into(), "SustainedDrift".into()],
1712                    "bounded Watch->Review promotion with persistence retained and corroboration relaxed only for this feature".into(),
1713                    if diagnostic.recovered_after_optimization {
1714                        "active_recovery".into()
1715                    } else {
1716                        "candidate_only".into()
1717                    },
1718                    "recall_recovery".into(),
1719                ),
1720                "watch_class_near_miss_below_numeric_gate" => (
1721                    vec!["BoundaryGrazing".into()],
1722                    if diagnostic.recovered_after_optimization {
1723                        "priority rescue from Watch->Review under high EWMA occupancy and bounded fragmentation".into()
1724                    } else {
1725                        "reject rescue because the feature never develops sufficient grammar-qualified motif support".into()
1726                    },
1727                    if diagnostic.recovered_after_optimization {
1728                        "active_recovery".into()
1729                    } else {
1730                        "rejected_for_insufficient_structure".into()
1731                    },
1732                    if diagnostic.recovered_after_optimization {
1733                        "recall_recovery".into()
1734                    } else {
1735                        "bounded_rejection".into()
1736                    },
1737                ),
1738                _ => (
1739                    vec!["Admissible".into()],
1740                    "no policy action accepted because the missed case lacks a recoverable DSFB structure".into(),
1741                    "rejected_for_insufficient_structure".into(),
1742                    "bounded_rejection".into(),
1743                ),
1744            };
1745
1746        entries.push(MinimalHeuristicEntry {
1747            heuristic_id: format!("failure_{}_{}", diagnostic.failure_run_index, diagnostic.exact_miss_rule),
1748            target_problem_type: "missed_failure".into(),
1749            target_identifier: diagnostic.failure_run_index.to_string(),
1750            target_feature_name: feature_name.clone(),
1751            target_motif_type: motif_type,
1752            target_grammar_states,
1753            semantic_requirement: "grammar-qualified semantic match required before any policy promotion".into(),
1754            policy_action,
1755            burden_effect_class,
1756            justification: format!(
1757                "Built from missed failure {} with nearest feature {:?}, operationalized feature {:?}, exact miss rule {}, bounded rescue recoverable={}.",
1758                diagnostic.failure_run_index,
1759                diagnostic.nearest_feature_name,
1760                diagnostic.optimized_feature_name,
1761                diagnostic.exact_miss_rule,
1762                diagnostic.bounded_rescue_would_recover,
1763            ),
1764            status,
1765        });
1766    }
1767
1768    let nuisance_entries = policy_operator_burden_contributions
1769        .iter()
1770        .filter(|row| {
1771            row.configuration_role == "baseline"
1772                && row.contribution_scope == "motif"
1773                && row.contribution_type == "review_escalate_burden"
1774        })
1775        .collect::<Vec<_>>();
1776    let mut nuisance_entries = nuisance_entries;
1777    nuisance_entries.sort_by(|left, right| {
1778        right
1779            .value
1780            .partial_cmp(&left.value)
1781            .unwrap_or(std::cmp::Ordering::Equal)
1782    });
1783    for nuisance in nuisance_entries.into_iter().take(4) {
1784        entries.push(MinimalHeuristicEntry {
1785            heuristic_id: format!("nuisance_{}", nuisance.name),
1786            target_problem_type: "nuisance_class".into(),
1787            target_identifier: nuisance.name.clone(),
1788            target_feature_name: None,
1789            target_motif_type: nuisance.name.clone(),
1790            target_grammar_states: match nuisance.name.as_str() {
1791                "recurrent_boundary_approach" => {
1792                    vec!["BoundaryGrazing".into(), "SustainedDrift".into()]
1793                }
1794                "watch_only_boundary_grazing" => vec!["BoundaryGrazing".into()],
1795                _ => vec!["grammar_filtered".into()],
1796            },
1797            semantic_requirement: "apply only after grammar filtering and semantic retrieval".into(),
1798            policy_action: match nuisance.name.as_str() {
1799                "recurrent_boundary_approach" => {
1800                    "keep default Watch ceiling unless persistence and bounded corroboration justify Review".into()
1801                }
1802                "watch_only_boundary_grazing" => {
1803                    "retain Watch-only handling to suppress isolated burden".into()
1804                }
1805                _ => "suppress isolated nuisance contribution before Review/Escalate promotion".into(),
1806            },
1807            burden_effect_class: "nuisance_suppression".into(),
1808            justification: format!(
1809                "Derived from baseline nuisance pattern {} with {:.0} pass-run Review/Escalate points.",
1810                nuisance.name, nuisance.value
1811            ),
1812            status: "active_suppression".into(),
1813        });
1814    }
1815
1816    entries.sort_by(|left, right| left.heuristic_id.cmp(&right.heuristic_id));
1817    entries.truncate(MAX_MINIMAL_HEURISTICS);
1818    entries
1819}
1820
1821fn build_policy_burden_summary(
1822    dataset: &PreparedDataset,
1823    optimized_dsa: &DsaEvaluation,
1824) -> Vec<PolicyBurdenSummaryRow> {
1825    let mut rows = optimized_dsa
1826        .motif_policy_contributions
1827        .iter()
1828        .map(|row| PolicyBurdenSummaryRow {
1829            scope: "motif".into(),
1830            name: row.motif_name.clone(),
1831            watch_points: row.watch_points,
1832            review_points: row.review_points,
1833            escalate_points: row.escalate_points,
1834            pass_review_escalate_points: row.pass_review_or_escalate_points,
1835            pre_failure_review_escalate_points: row.pre_failure_review_or_escalate_points,
1836            silent_suppression_points: row.silent_suppression_points,
1837            justification: "optimized selected-row motif burden summary".into(),
1838        })
1839        .collect::<Vec<_>>();
1840
1841    let mut feature_rows = optimized_dsa
1842        .traces
1843        .iter()
1844        .filter_map(|trace| {
1845            let mut watch_points = 0usize;
1846            let mut review_points = 0usize;
1847            let mut escalate_points = 0usize;
1848            let mut pass_review_escalate_points = 0usize;
1849            let mut pre_failure_review_escalate_points = 0usize;
1850            let mut silent_suppression_points = 0usize;
1851            for run_index in 0..trace.policy_state.len() {
1852                match trace.policy_state[run_index] {
1853                    DsaPolicyState::Silent => {
1854                        if trace.policy_suppressed_to_silent[run_index] {
1855                            silent_suppression_points += 1;
1856                        }
1857                    }
1858                    DsaPolicyState::Watch => watch_points += 1,
1859                    DsaPolicyState::Review => {
1860                        review_points += 1;
1861                        if dataset.labels[run_index] == -1 {
1862                            pass_review_escalate_points += 1;
1863                        }
1864                    }
1865                    DsaPolicyState::Escalate => {
1866                        escalate_points += 1;
1867                        if dataset.labels[run_index] == -1 {
1868                            pass_review_escalate_points += 1;
1869                        }
1870                    }
1871                }
1872                if dataset.labels[run_index] == 1 && trace.dsa_alert[run_index] {
1873                    pre_failure_review_escalate_points += 1;
1874                }
1875            }
1876            let investigation_points = review_points + escalate_points;
1877            (investigation_points > 0).then(|| PolicyBurdenSummaryRow {
1878                scope: "feature".into(),
1879                name: trace.feature_name.clone(),
1880                watch_points,
1881                review_points,
1882                escalate_points,
1883                pass_review_escalate_points,
1884                pre_failure_review_escalate_points,
1885                silent_suppression_points,
1886                justification: "optimized selected-row feature burden summary".into(),
1887            })
1888        })
1889        .collect::<Vec<_>>();
1890
1891    feature_rows.sort_by(|left, right| {
1892        (right.review_points + right.escalate_points)
1893            .cmp(&(left.review_points + left.escalate_points))
1894            .then_with(|| left.name.cmp(&right.name))
1895    });
1896    feature_rows.truncate(12);
1897    rows.extend(feature_rows);
1898    rows
1899}
1900
1901fn build_dsfb_vs_ewma_cases(
1902    dataset: &PreparedDataset,
1903    feature_bundles: &BTreeMap<usize, FeatureBundle<'_>>,
1904    optimized_by_failure: &BTreeMap<usize, &PerFailureRunDsaSignal>,
1905    metrics_by_failure: &BTreeMap<usize, &PerFailureRunSignal>,
1906    diagnostics_by_failure: &BTreeMap<usize, &MissedFailureDiagnosticRow>,
1907    missed_failure_diagnostics: &[MissedFailureDiagnosticRow],
1908    pre_failure_lookback_runs: usize,
1909) -> Vec<DsfbVsEwmaCase> {
1910    missed_failure_diagnostics
1911        .iter()
1912        .filter(|row| row.recovered_after_optimization)
1913        .filter_map(|diagnostic| {
1914            let feature_name = diagnostic
1915                .optimized_feature_name
1916                .clone()
1917                .or_else(|| diagnostic.nearest_feature_name.clone())?;
1918            let bundle = feature_bundles
1919                .values()
1920                .find(|row| row.residual.feature_name == feature_name)?;
1921            let optimized_row = optimized_by_failure.get(&diagnostic.failure_run_index).copied()?;
1922            let metrics_row = metrics_by_failure.get(&diagnostic.failure_run_index).copied()?;
1923            let start = diagnostic
1924                .failure_run_index
1925                .saturating_sub(pre_failure_lookback_runs);
1926            let window = (start..diagnostic.failure_run_index)
1927                .map(|run_index| DsfbVsEwmaWindowPoint {
1928                    run_index,
1929                    timestamp: dataset.timestamps[run_index]
1930                        .format("%Y-%m-%d %H:%M:%S")
1931                        .to_string(),
1932                    label: dataset.labels[run_index],
1933                    ewma_value: bundle.ewma.ewma[run_index],
1934                    ewma_threshold: bundle.ewma.threshold,
1935                    ewma_alarm: bundle.ewma.alarm[run_index],
1936                    residual: bundle.residual.residuals[run_index],
1937                    drift: bundle.sign.drift[run_index],
1938                    slew: bundle.sign.slew[run_index],
1939                    motif_label: bundle.motif.labels[run_index].as_lowercase().into(),
1940                    grammar_state: failure_grammar_state_label(bundle.grammar, run_index).into(),
1941                    policy_state: bundle.optimized_dsa.policy_state[run_index]
1942                        .as_lowercase()
1943                        .into(),
1944                })
1945                .collect::<Vec<_>>();
1946            let explanation = if metrics_row.earliest_ewma_run.is_some() {
1947                format!(
1948                    "EWMA also detected failure {} with lead {:?}, so DSFB does not add scalar coverage here. The DSFB recovery adds structure instead: feature {} shows motif {} under grammar {} and is promoted by a bounded rescue tied to {}.",
1949                    diagnostic.failure_run_index,
1950                    metrics_row.ewma_lead_runs,
1951                    feature_name,
1952                    dominant_motif_in_window(bundle.motif, start, diagnostic.failure_run_index),
1953                    dominant_grammar_state_in_window(bundle.grammar, start, diagnostic.failure_run_index),
1954                    diagnostic.exact_miss_rule,
1955                )
1956            } else {
1957                format!(
1958                    "EWMA missed failure {}, while DSFB recovered it through feature {} with motif {} under grammar {}.",
1959                    diagnostic.failure_run_index,
1960                    feature_name,
1961                    dominant_motif_in_window(bundle.motif, start, diagnostic.failure_run_index),
1962                    dominant_grammar_state_in_window(bundle.grammar, start, diagnostic.failure_run_index),
1963                )
1964            };
1965            let _ = diagnostics_by_failure;
1966
1967            Some(DsfbVsEwmaCase {
1968                failure_id: diagnostic.failure_run_index,
1969                failure_timestamp: optimized_row.failure_timestamp.clone(),
1970                recovered: true,
1971                recovered_feature_name: feature_name,
1972                baseline_miss_rule: diagnostic.exact_miss_rule.clone(),
1973                ewma_detected: metrics_row.earliest_ewma_run.is_some(),
1974                ewma_lead_runs: metrics_row.ewma_lead_runs,
1975                optimized_dsa_lead_runs: optimized_row.dsa_lead_runs,
1976                explanation,
1977                window,
1978            })
1979        })
1980        .collect()
1981}
1982
1983fn top_feature_activity_for_failure(
1984    feature_bundles: &BTreeMap<usize, FeatureBundle<'_>>,
1985    failure_index: usize,
1986    pre_failure_lookback_runs: usize,
1987    limit: usize,
1988    require_nonzero_score: bool,
1989) -> Vec<FeatureActivityCandidate> {
1990    let start = failure_index.saturating_sub(pre_failure_lookback_runs);
1991    let mut candidates = feature_bundles
1992        .iter()
1993        .map(|(&feature_index, bundle)| {
1994            let max_dsa_score = bundle.baseline_dsa.dsa_score[start..failure_index]
1995                .iter()
1996                .copied()
1997                .fold(0.0, f64::max);
1998            let motif_hits = bundle.baseline_dsa.motif_hit[start..failure_index]
1999                .iter()
2000                .filter(|flag| **flag)
2001                .count();
2002            let pressure_hits = (start..failure_index)
2003                .filter(|&run_index| {
2004                    matches!(
2005                        failure_grammar_state_label(bundle.grammar, run_index),
2006                        "BoundaryGrazing"
2007                            | "SustainedDrift"
2008                            | "TransientViolation"
2009                            | "PersistentViolation"
2010                    )
2011                })
2012                .count();
2013            let max_policy_state = dominant_policy_state_in_window(
2014                &bundle.baseline_dsa.policy_state[start..failure_index],
2015            )
2016            .into();
2017            FeatureActivityCandidate {
2018                feature_index,
2019                feature_name: bundle.residual.feature_name.clone(),
2020                ranking_score_proxy: max_dsa_score
2021                    + 0.25 * motif_hits as f64
2022                    + 0.25 * pressure_hits as f64,
2023                max_dsa_score,
2024                max_policy_state,
2025                motif_hits,
2026                pressure_hits,
2027            }
2028        })
2029        .filter(|candidate| !require_nonzero_score || candidate.ranking_score_proxy > 0.0)
2030        .collect::<Vec<_>>();
2031    candidates.sort_by(|left, right| {
2032        right
2033            .ranking_score_proxy
2034            .partial_cmp(&left.ranking_score_proxy)
2035            .unwrap_or(std::cmp::Ordering::Equal)
2036            .then_with(|| left.feature_name.cmp(&right.feature_name))
2037    });
2038    candidates.truncate(limit);
2039    candidates
2040}
2041
2042fn semantic_labels_in_window(
2043    semantic_layer: &SemanticLayer,
2044    feature_name: &str,
2045    start: usize,
2046    failure_index: usize,
2047) -> Vec<String> {
2048    let mut labels = semantic_layer
2049        .semantic_matches
2050        .iter()
2051        .filter(|row| {
2052            row.feature_name == feature_name
2053                && row.run_index >= start
2054                && row.run_index < failure_index
2055        })
2056        .map(|row| row.heuristic_name.clone())
2057        .collect::<BTreeSet<_>>()
2058        .into_iter()
2059        .collect::<Vec<_>>();
2060    if labels.is_empty() {
2061        labels.push("none".into());
2062    }
2063    labels
2064}
2065
2066fn feature_failure_explanation(
2067    bundle: &FeatureBundle<'_>,
2068    start: usize,
2069    failure_index: usize,
2070    diagnostic: Option<&MissedFailureDiagnosticRow>,
2071    semantic_labels: &[String],
2072) -> (String, String) {
2073    let has_non_stable_motif = bundle.motif.labels[start..failure_index]
2074        .iter()
2075        .any(|label| *label != DsfbMotifClass::StableAdmissible);
2076    let has_pressure = (start..failure_index).any(|run_index| {
2077        matches!(
2078            failure_grammar_state_label(bundle.grammar, run_index),
2079            "BoundaryGrazing" | "SustainedDrift" | "TransientViolation" | "PersistentViolation"
2080        )
2081    });
2082    let has_semantic = semantic_labels.iter().any(|label| label != "none");
2083    let has_review = bundle.baseline_dsa.policy_state[start..failure_index]
2084        .iter()
2085        .any(|state| matches!(state, DsaPolicyState::Review | DsaPolicyState::Escalate));
2086
2087    if !has_non_stable_motif {
2088        (
2089            "syntax".into(),
2090            "No non-trivial DSFB motif was detected in the failure lookback window.".into(),
2091        )
2092    } else if !has_pressure {
2093        (
2094            "grammar".into(),
2095            "A motif candidate was present but never qualified by a non-admissible envelope interaction.".into(),
2096        )
2097    } else if !has_semantic {
2098        (
2099            "semantics".into(),
2100            "Syntax and grammar were present, but no grammar-qualified semantic retrieval survived the heuristics bank.".into(),
2101        )
2102    } else if !has_review {
2103        (
2104            "policy".into(),
2105            diagnostic
2106                .map(|row| {
2107                    format!(
2108                        "Semantic evidence existed but policy never promoted beyond {} because of {}.",
2109                        row.nearest_feature_policy_state
2110                            .clone()
2111                            .unwrap_or_else(|| "silent".into()),
2112                        row.exact_miss_rule
2113                    )
2114                })
2115                .unwrap_or_else(|| {
2116                    "Semantic evidence existed but policy never promoted to Review/Escalate.".into()
2117                }),
2118        )
2119    } else {
2120        (
2121            "support".into(),
2122            "The feature carried supportive structure but was not the decisive failure-localized signal.".into(),
2123        )
2124    }
2125}
2126
2127fn failure_stage_label(diagnostic: Option<&MissedFailureDiagnosticRow>) -> String {
2128    match diagnostic {
2129        Some(row) if row.ranking_exclusion => "ranking".into(),
2130        Some(row) if row.cohort_selection => "cohort_selection".into(),
2131        Some(row) if row.policy_suppression => "policy".into(),
2132        Some(row) if row.fragmentation_ceiling => "policy_fragmentation".into(),
2133        Some(row) if row.directional_consistency_gate => "policy_directionality".into(),
2134        Some(row) if row.persistence_gate => "policy_persistence".into(),
2135        Some(row) if row.corroboration_threshold => "policy_corroboration".into(),
2136        Some(row) if row.rescue_gate_not_activating => "rescue".into(),
2137        Some(_) => "policy".into(),
2138        None => "unclassified".into(),
2139    }
2140}
2141
2142fn failure_explanation_text(
2143    diagnostic: Option<&MissedFailureDiagnosticRow>,
2144    optimized_row: &PerFailureRunDsaSignal,
2145) -> String {
2146    match diagnostic {
2147        Some(row) if row.recovered_after_optimization => format!(
2148            "Baseline DSA missed the failure because of {} on feature {:?}; the bounded recovery layer later recovered it via {:?}.",
2149            row.exact_miss_rule, row.nearest_feature_name, row.optimized_feature_name
2150        ),
2151        Some(row) => format!(
2152            "Baseline DSA missed the failure because of {} on feature {:?}; no bounded recovery rule recovered it.",
2153            row.exact_miss_rule, row.nearest_feature_name
2154        ),
2155        None if optimized_row.earliest_dsa_run.is_some() => {
2156            "The failure was recovered during optimization, but no baseline miss diagnostic row was available.".into()
2157        }
2158        None => "The failure remains missed and no detailed diagnostic row was available.".into(),
2159    }
2160}
2161
2162fn miss_reason_class(
2163    diagnostic: Option<&MissedFailureDiagnosticRow>,
2164    optimized_row: &PerFailureRunDsaSignal,
2165) -> &'static str {
2166    match diagnostic {
2167        Some(row) if row.ranking_exclusion || row.cohort_selection => "feature_exclusion",
2168        Some(row) if row.fragmentation_ceiling => "fragmentation_ceiling",
2169        Some(row)
2170            if row.policy_suppression
2171                || row.directional_consistency_gate
2172                || row.persistence_gate
2173                || row.corroboration_threshold
2174                || row.rescue_gate_not_activating =>
2175        {
2176            "policy_suppression"
2177        }
2178        Some(_) if optimized_row.earliest_dsa_run.is_none() => "semantic_unresolved",
2179        Some(_) => "grammar_rejection",
2180        None if optimized_row.earliest_dsa_run.is_some() => "recoverable",
2181        None => "feature_absence",
2182    }
2183}
2184
2185fn scalar_detection_explanation(
2186    layer_name: &str,
2187    detected: bool,
2188    lead_runs: Option<usize>,
2189    supporting_features: &[String],
2190) -> String {
2191    if detected {
2192        format!(
2193            "{} detected the failure with lead {:?}; supporting features in the lookback were {}.",
2194            layer_name,
2195            lead_runs,
2196            if supporting_features.is_empty() {
2197                "none".into()
2198            } else {
2199                supporting_features.join(",")
2200            }
2201        )
2202    } else {
2203        format!("{layer_name} did not detect the failure in the configured lookback window.")
2204    }
2205}
2206
2207fn scalar_supporting_features(
2208    feature_bundles: &BTreeMap<usize, FeatureBundle<'_>>,
2209    start: usize,
2210    failure_index: usize,
2211    mode: ScalarSupportMode,
2212) -> Vec<String> {
2213    let mut scored = feature_bundles
2214        .values()
2215        .map(|bundle| {
2216            let score = match mode {
2217                ScalarSupportMode::Threshold => bundle.residual.threshold_alarm
2218                    [start..failure_index]
2219                    .iter()
2220                    .filter(|flag| **flag)
2221                    .count(),
2222                ScalarSupportMode::Ewma => bundle.ewma.alarm[start..failure_index]
2223                    .iter()
2224                    .filter(|flag| **flag)
2225                    .count(),
2226            };
2227            (bundle.residual.feature_name.clone(), score)
2228        })
2229        .filter(|(_, score)| *score > 0)
2230        .collect::<Vec<_>>();
2231    scored.sort_by(|left, right| right.1.cmp(&left.1).then_with(|| left.0.cmp(&right.0)));
2232    scored.into_iter().take(3).map(|(name, _)| name).collect()
2233}
2234
2235fn grounding_candidate_features(
2236    baseline_dsa: &DsaEvaluation,
2237    optimized_dsa: &DsaEvaluation,
2238    missed_failure_diagnostics: &[MissedFailureDiagnosticRow],
2239    policy_operator_burden_contributions: &[OperatorBurdenContributionRow],
2240    failure_cases: &[FailureCaseReport],
2241) -> Vec<usize> {
2242    let mut features = BTreeSet::new();
2243    for spec in FEATURE_ROLE_LOCK {
2244        if let Some(feature_index) = feature_index_from_name(spec.feature_name) {
2245            features.insert(feature_index);
2246        }
2247    }
2248    for row in &baseline_dsa.per_failure_run_signals {
2249        if let Some(feature_index) = row.max_dsa_score_feature_index {
2250            features.insert(feature_index);
2251        }
2252        if let Some(feature_index) = row.earliest_dsa_feature_index {
2253            features.insert(feature_index);
2254        }
2255    }
2256    for row in &optimized_dsa.per_failure_run_signals {
2257        if let Some(feature_index) = row.earliest_dsa_feature_index {
2258            features.insert(feature_index);
2259        }
2260    }
2261    for row in missed_failure_diagnostics {
2262        if let Some(feature_name) = row.nearest_feature_name.as_deref() {
2263            if let Some(index) = feature_index_from_name(feature_name) {
2264                features.insert(index);
2265            }
2266        }
2267        if let Some(feature_name) = row.optimized_feature_name.as_deref() {
2268            if let Some(index) = feature_index_from_name(feature_name) {
2269                features.insert(index);
2270            }
2271        }
2272    }
2273    for case in failure_cases {
2274        for feature in &case.top_contributing_features {
2275            features.insert(feature.feature_index);
2276        }
2277    }
2278    let mut burden_features = policy_operator_burden_contributions
2279        .iter()
2280        .filter(|row| row.configuration_role == "optimized" && row.contribution_scope == "feature")
2281        .filter_map(|row| feature_index_from_name(&row.name).map(|index| (index, row.value)))
2282        .collect::<Vec<_>>();
2283    burden_features.sort_by(|left, right| {
2284        right
2285            .1
2286            .partial_cmp(&left.1)
2287            .unwrap_or(std::cmp::Ordering::Equal)
2288    });
2289    for (feature_index, _) in burden_features.into_iter().take(12) {
2290        features.insert(feature_index);
2291    }
2292    features.into_iter().collect()
2293}
2294
2295fn semantic_hit_count(
2296    semantic_layer: &SemanticLayer,
2297    feature_name: &str,
2298    failure_window_mask: &[bool],
2299    in_failure_window: bool,
2300) -> usize {
2301    semantic_layer
2302        .semantic_matches
2303        .iter()
2304        .filter(|row| {
2305            row.feature_name == feature_name
2306                && failure_window_mask[row.run_index] == in_failure_window
2307        })
2308        .count()
2309}
2310
2311fn pressure_hit_count(
2312    grammar_trace: &FeatureGrammarTrace,
2313    failure_window_mask: &[bool],
2314    in_failure_window: bool,
2315) -> usize {
2316    grammar_trace
2317        .raw_states
2318        .iter()
2319        .enumerate()
2320        .filter(|(run_index, _)| failure_window_mask[*run_index] == in_failure_window)
2321        .filter(|(run_index, _)| {
2322            matches!(
2323                failure_grammar_state_label(grammar_trace, *run_index),
2324                "BoundaryGrazing" | "SustainedDrift" | "TransientViolation" | "PersistentViolation"
2325            )
2326        })
2327        .count()
2328}
2329
2330fn masked_mean_abs(values: &[f64], mask: &[bool], select_value: bool) -> f64 {
2331    let selected = values
2332        .iter()
2333        .zip(mask)
2334        .filter(|(_, flag)| **flag == select_value)
2335        .map(|(value, _)| value.abs())
2336        .collect::<Vec<_>>();
2337    mean(&selected).unwrap_or(0.0)
2338}
2339
2340fn dominant_motif_for_mask(
2341    motif_trace: &FeatureMotifTrace,
2342    mask: &[bool],
2343    select_value: bool,
2344) -> String {
2345    let mut counts = BTreeMap::<&'static str, usize>::new();
2346    for (run_index, label) in motif_trace.labels.iter().enumerate() {
2347        if mask[run_index] != select_value {
2348            continue;
2349        }
2350        *counts.entry(label.as_lowercase()).or_default() += 1;
2351    }
2352    counts
2353        .into_iter()
2354        .max_by(|left, right| left.1.cmp(&right.1).then_with(|| right.0.cmp(left.0)))
2355        .map(|(label, _)| label.to_string())
2356        .unwrap_or_else(|| "stable_admissible".into())
2357}
2358
2359fn dominant_grammar_state_for_mask(
2360    grammar_trace: &FeatureGrammarTrace,
2361    mask: &[bool],
2362    select_value: bool,
2363) -> String {
2364    let mut counts = BTreeMap::<&'static str, usize>::new();
2365    for run_index in 0..grammar_trace.raw_states.len() {
2366        if mask[run_index] != select_value {
2367            continue;
2368        }
2369        *counts
2370            .entry(failure_grammar_state_label(grammar_trace, run_index))
2371            .or_default() += 1;
2372    }
2373    counts
2374        .into_iter()
2375        .max_by(|left, right| left.1.cmp(&right.1).then_with(|| right.0.cmp(left.0)))
2376        .map(|(label, _)| label.to_string())
2377        .unwrap_or_else(|| "Admissible".into())
2378}
2379
2380fn grounded_motif_type(
2381    dominant_dsfb_motif: &str,
2382    dominant_grammar_state: &str,
2383    failure_local_recovery_case_count: usize,
2384    failure_semantic_hits: usize,
2385    pass_semantic_hits: usize,
2386    failure_pressure_hits: usize,
2387    pass_pressure_hits: usize,
2388    mean_abs_drift_failure: f64,
2389    mean_abs_slew_failure: f64,
2390) -> &'static str {
2391    if failure_semantic_hits == 0 && failure_pressure_hits == 0 {
2392        return "null";
2393    }
2394    if (dominant_grammar_state == "Recovery" && failure_semantic_hits > 0)
2395        || (failure_local_recovery_case_count > 0 && failure_semantic_hits >= pass_semantic_hits)
2396    {
2397        return "recovery_pattern";
2398    }
2399    if pass_semantic_hits > failure_semantic_hits.saturating_mul(3) && failure_pressure_hits <= 1 {
2400        return "noise_like";
2401    }
2402    match dominant_dsfb_motif {
2403        "pre_failure_slow_drift" => "slow_drift_precursor",
2404        "recurrent_boundary_approach" | "watch_only_boundary_grazing" => "boundary_grazing",
2405        "transition_excursion" => {
2406            if mean_abs_slew_failure > mean_abs_drift_failure {
2407                "transient_excursion"
2408            } else {
2409                "burst_instability"
2410            }
2411        }
2412        "persistent_instability_cluster" => "persistent_instability",
2413        "transition_cluster_support" => "burst_instability",
2414        _ if failure_pressure_hits > pass_pressure_hits
2415            && mean_abs_drift_failure > mean_abs_slew_failure =>
2416        {
2417            "slow_drift_precursor"
2418        }
2419        _ if dominant_grammar_state == "BoundaryGrazing" => "boundary_grazing",
2420        _ if failure_pressure_hits > pass_pressure_hits => "persistent_instability",
2421        _ => "noise_like",
2422    }
2423}
2424
2425fn grounded_motif_type_for_window(
2426    bundle: &FeatureBundle<'_>,
2427    start: usize,
2428    failure_index: usize,
2429) -> &'static str {
2430    let window_mask = (0..bundle.motif.labels.len())
2431        .map(|run_index| run_index >= start && run_index < failure_index)
2432        .collect::<Vec<_>>();
2433    grounded_motif_type(
2434        dominant_motif_for_mask(bundle.motif, &window_mask, true).as_str(),
2435        dominant_grammar_state_in_window(bundle.grammar, start, failure_index).as_str(),
2436        0,
2437        bundle.motif.labels[start..failure_index]
2438            .iter()
2439            .filter(|label| **label != DsfbMotifClass::StableAdmissible)
2440            .count(),
2441        0,
2442        pressure_hit_count(bundle.grammar, &window_mask, true),
2443        0,
2444        mean_abs(&bundle.sign.drift[start..failure_index]),
2445        mean_abs(&bundle.sign.slew[start..failure_index]),
2446    )
2447}
2448
2449fn build_failure_window_mask(
2450    len: usize,
2451    failure_indices: &[usize],
2452    pre_failure_lookback_runs: usize,
2453) -> Vec<bool> {
2454    let mut mask = vec![false; len];
2455    for &failure_index in failure_indices {
2456        let start = failure_index.saturating_sub(pre_failure_lookback_runs);
2457        for flag in &mut mask[start..failure_index] {
2458            *flag = true;
2459        }
2460    }
2461    mask
2462}
2463
2464fn dominant_motif_in_window(
2465    motif_trace: &FeatureMotifTrace,
2466    start: usize,
2467    failure_index: usize,
2468) -> String {
2469    let mask = (0..motif_trace.labels.len())
2470        .map(|run_index| run_index >= start && run_index < failure_index)
2471        .collect::<Vec<_>>();
2472    dominant_motif_for_mask(motif_trace, &mask, true)
2473}
2474
2475fn dominant_grammar_state_in_window(
2476    grammar_trace: &FeatureGrammarTrace,
2477    start: usize,
2478    failure_index: usize,
2479) -> String {
2480    let mut counts = BTreeMap::<&'static str, usize>::new();
2481    for run_index in start..failure_index {
2482        *counts
2483            .entry(failure_grammar_state_label(grammar_trace, run_index))
2484            .or_default() += 1;
2485    }
2486    counts
2487        .into_iter()
2488        .max_by(|left, right| left.1.cmp(&right.1).then_with(|| right.0.cmp(left.0)))
2489        .map(|(label, _)| label.to_string())
2490        .unwrap_or_else(|| "Admissible".into())
2491}
2492
2493fn dominant_policy_state_in_window(states: &[DsaPolicyState]) -> &'static str {
2494    if states
2495        .iter()
2496        .any(|state| matches!(state, DsaPolicyState::Escalate))
2497    {
2498        "escalate"
2499    } else if states
2500        .iter()
2501        .any(|state| matches!(state, DsaPolicyState::Review))
2502    {
2503        "review"
2504    } else if states
2505        .iter()
2506        .any(|state| matches!(state, DsaPolicyState::Watch))
2507    {
2508        "watch"
2509    } else {
2510        "silent"
2511    }
2512}
2513
2514fn failure_grammar_state_label(
2515    grammar_trace: &FeatureGrammarTrace,
2516    run_index: usize,
2517) -> &'static str {
2518    if grammar_trace.raw_states[run_index] == GrammarState::Violation {
2519        if grammar_trace.persistent_violation[run_index] {
2520            "PersistentViolation"
2521        } else {
2522            "TransientViolation"
2523        }
2524    } else if grammar_trace.raw_states[run_index] == GrammarState::Boundary {
2525        if grammar_trace.raw_reasons[run_index] == GrammarReason::SustainedOutwardDrift {
2526            "SustainedDrift"
2527        } else {
2528            "BoundaryGrazing"
2529        }
2530    } else if run_index > 0
2531        && matches!(
2532            failure_grammar_state_label(grammar_trace, run_index - 1),
2533            "BoundaryGrazing" | "SustainedDrift" | "TransientViolation" | "PersistentViolation"
2534        )
2535    {
2536        "Recovery"
2537    } else {
2538        "Admissible"
2539    }
2540}
2541
2542fn feature_index_from_name(feature_name: &str) -> Option<usize> {
2543    feature_name
2544        .strip_prefix('S')
2545        .and_then(|value| value.parse::<usize>().ok())
2546        .and_then(|value| value.checked_sub(1))
2547}
2548
2549fn mean(values: &[f64]) -> Option<f64> {
2550    (!values.is_empty()).then_some(values.iter().sum::<f64>() / values.len() as f64)
2551}
2552
2553fn mean_abs(values: &[f64]) -> f64 {
2554    if values.is_empty() {
2555        0.0
2556    } else {
2557        values.iter().map(|value| value.abs()).sum::<f64>() / values.len() as f64
2558    }
2559}
2560
2561fn episode_ranges(signal: &[bool]) -> Vec<(usize, usize)> {
2562    let mut episodes = Vec::new();
2563    let mut start = None::<usize>;
2564    for (run_index, flag) in signal.iter().copied().enumerate() {
2565        match (start, flag) {
2566            (None, true) => start = Some(run_index),
2567            (Some(episode_start), false) => {
2568                episodes.push((episode_start, run_index - 1));
2569                start = None;
2570            }
2571            _ => {}
2572        }
2573    }
2574    if let Some(episode_start) = start {
2575        episodes.push((episode_start, signal.len().saturating_sub(1)));
2576    }
2577    episodes
2578}
2579
2580enum ScalarSupportMode {
2581    Threshold,
2582    Ewma,
2583}
2584
2585#[cfg(test)]
2586mod tests {
2587    use super::*;
2588
2589    #[test]
2590    fn grouped_semiotics_rejection_helper_is_deterministic() {
2591        let definitions = vec![
2592            GroupDefinitionRecord {
2593                group_name: "group_a".into(),
2594                member_features: "S001,S002".into(),
2595                member_roles: "a,b".into(),
2596                preferred_motifs: "slow_drift_precursor".into(),
2597                empirical_basis: "fixture".into(),
2598                group_size: 2,
2599                rescue_eligible_member_count: 1,
2600                highest_rescue_priority: "high".into(),
2601                semantic_match_count: 0,
2602                dominant_group_heuristic: None,
2603                pressure_run_count: 0,
2604                violation_run_count: 0,
2605                mean_active_feature_count: 0.0,
2606                mean_envelope_separation: 0.0,
2607                coactivation_member_threshold: 2,
2608                minimum_failure_coactivation_runs: 2,
2609                failure_coactivation_run_count: 1,
2610                pass_coactivation_run_count: 0,
2611                validated: false,
2612                rejection_reason: Some("failure co-activation below threshold".into()),
2613            },
2614            GroupDefinitionRecord {
2615                group_name: "group_b".into(),
2616                member_features: "S003,S004".into(),
2617                member_roles: "c,d".into(),
2618                preferred_motifs: "persistent_instability".into(),
2619                empirical_basis: "fixture".into(),
2620                group_size: 2,
2621                rescue_eligible_member_count: 1,
2622                highest_rescue_priority: "medium".into(),
2623                semantic_match_count: 3,
2624                dominant_group_heuristic: Some("persistent_instability_cluster".into()),
2625                pressure_run_count: 3,
2626                violation_run_count: 1,
2627                mean_active_feature_count: 2.0,
2628                mean_envelope_separation: 0.8,
2629                coactivation_member_threshold: 2,
2630                minimum_failure_coactivation_runs: 2,
2631                failure_coactivation_run_count: 2,
2632                pass_coactivation_run_count: 0,
2633                validated: true,
2634                rejection_reason: None,
2635            },
2636        ];
2637
2638        assert!(!grouped_semiotics_rejected(&definitions));
2639        let validated = validated_group_definitions(&definitions);
2640        assert_eq!(validated.len(), 1);
2641        assert_eq!(validated[0].group_name, "group_b");
2642    }
2643
2644    #[test]
2645    fn grounded_motif_type_prefers_null_without_failure_structure() {
2646        assert_eq!(
2647            grounded_motif_type("stable_admissible", "Admissible", 0, 0, 0, 0, 0, 0.0, 0.0),
2648            "null"
2649        );
2650        assert_eq!(
2651            grounded_motif_type(
2652                "recurrent_boundary_approach",
2653                "BoundaryGrazing",
2654                0,
2655                2,
2656                10,
2657                1,
2658                5,
2659                0.1,
2660                0.1
2661            ),
2662            "noise_like"
2663        );
2664        assert_eq!(
2665            grounded_motif_type(
2666                "persistent_instability_cluster",
2667                "Recovery",
2668                0,
2669                3,
2670                1,
2671                2,
2672                0,
2673                0.1,
2674                0.2
2675            ),
2676            "recovery_pattern"
2677        );
2678        assert_eq!(
2679            grounded_motif_type("stable_admissible", "Admissible", 1, 4, 1, 6, 0, 0.1, 0.2),
2680            "recovery_pattern"
2681        );
2682    }
2683}