use std::collections::BTreeMap;
use omena_cascade::{
DiagnosticFrameFootprintV0, RecheckSelectionV0, compute_edit_footprint, select_recheck_set,
};
use omena_incremental::{
IncrementalGraphInputV0, IncrementalNodeInputV0, IncrementalRevisionV0,
OmenaIncrementalDatabaseV0,
};
use omena_query::{
OmenaParserStyleDialect, OmenaQueryStyleFrameRefreshFactsV0,
OmenaQueryStyleFrameRefreshParseCacheV0,
summarize_omena_query_style_frame_refresh_facts_with_reuse,
};
use serde::Serialize;
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct FrameAwareRefreshReportV0 {
pub schema_version: &'static str,
pub product: &'static str,
pub feature_gate: &'static str,
pub selective_refresh_enabled: bool,
pub edited_module_count: usize,
pub selected_diagnostic_instance_ids: Vec<String>,
pub skipped_diagnostic_instance_ids: Vec<String>,
pub layer_marker: &'static str,
}
#[derive(Debug, Clone, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct FrameAwareRefreshComparisonV0 {
pub schema_version: &'static str,
pub product: &'static str,
pub fixed_workspace_fixture: &'static str,
pub diagnostic_frame_count: usize,
pub edited_module_count: usize,
pub unconditional_selected_count: usize,
pub selective_selected_count: usize,
pub skipped_diagnostic_count: usize,
pub selected_work_reduction_count: usize,
pub selected_work_reduction_ratio: f64,
pub measured_latency_proxy: &'static str,
pub selective_refresh_enabled_by_default: bool,
pub feature_gate: &'static str,
pub disable_gate: &'static str,
pub layer_marker: &'static str,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FrameAwareStyleModuleInputV0 {
pub module_id: String,
pub source: String,
pub dialect: OmenaParserStyleDialect,
}
#[derive(Default)]
pub struct FrameAwareRefreshRuntimeV0 {
revision: u64,
incremental_database: OmenaIncrementalDatabaseV0,
parse_caches_by_module_id: BTreeMap<String, OmenaQueryStyleFrameRefreshParseCacheV0>,
}
impl FrameAwareRefreshRuntimeV0 {
pub fn refresh_diagnostics_with_style_modules_policy(
&mut self,
frames: &[DiagnosticFrameFootprintV0],
modules: &[FrameAwareStyleModuleInputV0],
selective_refresh_enabled: bool,
) -> FrameAwareRefreshReportV0 {
let graph = self.frame_refresh_graph_input(modules);
let update = self
.incremental_database
.plan_and_upsert_graph_input(&graph);
let dirty_module_ids = update
.incremental_plan
.nodes
.iter()
.filter(|node| node.dirty)
.map(|node| node.id.clone())
.collect::<Vec<_>>();
let edited_module_count = dirty_module_ids.len();
let selection = if selective_refresh_enabled {
select_recheck_set_for_module_ids(frames, dirty_module_ids)
} else {
select_recheck_set_for_module_ids(frames, frames_to_module_ids(frames))
};
FrameAwareRefreshReportV0 {
schema_version: "0",
product: "omena-lsp-server.frame-aware-refresh",
feature_gate: "OMENA_LSP_ENABLE_FRAME_AWARE_REFRESH",
selective_refresh_enabled,
edited_module_count,
selected_diagnostic_instance_ids: selection.selected_diagnostic_instance_ids,
skipped_diagnostic_instance_ids: selection.skipped_diagnostic_instance_ids,
layer_marker: "frame-rule",
}
}
fn frame_refresh_graph_input(
&mut self,
modules: &[FrameAwareStyleModuleInputV0],
) -> IncrementalGraphInputV0 {
self.revision = self.revision.saturating_add(1);
IncrementalGraphInputV0 {
revision: IncrementalRevisionV0 {
value: self.revision,
},
nodes: modules
.iter()
.map(|module| self.frame_refresh_node_input(module))
.collect(),
}
}
fn frame_refresh_node_input(
&mut self,
module: &FrameAwareStyleModuleInputV0,
) -> IncrementalNodeInputV0 {
let cache = self
.parse_caches_by_module_id
.entry(module.module_id.clone())
.or_default();
let facts = summarize_omena_query_style_frame_refresh_facts_with_reuse(
module.source.as_str(),
module.dialect,
cache,
);
let dependency_ids = facts.dependency_ids.clone();
let digest = frame_refresh_digest(module, &facts);
IncrementalNodeInputV0 {
id: module.module_id.clone(),
digest,
dependency_ids,
}
}
}
pub fn refresh_diagnostics_with_frame(
frames: &[DiagnosticFrameFootprintV0],
edited_module_ids: Vec<String>,
) -> FrameAwareRefreshReportV0 {
let selective_refresh_enabled = frame_aware_refresh_enabled_from_env();
refresh_diagnostics_with_frame_policy(frames, edited_module_ids, selective_refresh_enabled)
}
pub fn refresh_diagnostics_with_frame_policy(
frames: &[DiagnosticFrameFootprintV0],
edited_module_ids: Vec<String>,
selective_refresh_enabled: bool,
) -> FrameAwareRefreshReportV0 {
let edited_module_count = edited_module_ids.len();
let selection = if selective_refresh_enabled {
select_recheck_set_for_module_ids(frames, edited_module_ids)
} else {
select_recheck_set_for_module_ids(frames, frames_to_module_ids(frames))
};
FrameAwareRefreshReportV0 {
schema_version: "0",
product: "omena-lsp-server.frame-aware-refresh",
feature_gate: "OMENA_LSP_ENABLE_FRAME_AWARE_REFRESH",
selective_refresh_enabled,
edited_module_count,
selected_diagnostic_instance_ids: selection.selected_diagnostic_instance_ids,
skipped_diagnostic_instance_ids: selection.skipped_diagnostic_instance_ids,
layer_marker: "frame-rule",
}
}
pub fn compare_frame_refresh_against_unconditional_baseline(
frames: &[DiagnosticFrameFootprintV0],
edited_module_ids: Vec<String>,
) -> FrameAwareRefreshComparisonV0 {
let unconditional =
refresh_diagnostics_with_frame_policy(frames, edited_module_ids.clone(), false);
let selective = refresh_diagnostics_with_frame_policy(frames, edited_module_ids, true);
let unconditional_selected_count = unconditional.selected_diagnostic_instance_ids.len();
let selective_selected_count = selective.selected_diagnostic_instance_ids.len();
let selected_work_reduction_count =
unconditional_selected_count.saturating_sub(selective_selected_count);
let selected_work_reduction_ratio = if unconditional_selected_count == 0 {
0.0
} else {
selected_work_reduction_count as f64 / unconditional_selected_count as f64
};
FrameAwareRefreshComparisonV0 {
schema_version: "0",
product: "omena-lsp-server.frame-aware-refresh-comparison",
fixed_workspace_fixture: "m4-alpha-fixed-workspace-frame-refresh",
diagnostic_frame_count: frames.len(),
edited_module_count: unconditional.edited_module_count,
unconditional_selected_count,
selective_selected_count,
skipped_diagnostic_count: selective.skipped_diagnostic_instance_ids.len(),
selected_work_reduction_count,
selected_work_reduction_ratio,
measured_latency_proxy: "selected-diagnostic-work-count",
selective_refresh_enabled_by_default: frame_aware_refresh_enabled(false, false),
feature_gate: "OMENA_LSP_ENABLE_FRAME_AWARE_REFRESH",
disable_gate: "OMENA_LSP_DISABLE_FRAME_AWARE_REFRESH",
layer_marker: "frame-rule",
}
}
fn frames_to_module_ids(frames: &[DiagnosticFrameFootprintV0]) -> Vec<String> {
frames
.iter()
.flat_map(|frame| frame.evidence_module_ids.iter().cloned())
.collect()
}
fn select_recheck_set_for_module_ids(
frames: &[DiagnosticFrameFootprintV0],
module_ids: Vec<String>,
) -> RecheckSelectionV0 {
let footprint = compute_edit_footprint(module_ids);
select_recheck_set(frames, &footprint)
}
fn frame_refresh_digest(
module: &FrameAwareStyleModuleInputV0,
facts: &OmenaQueryStyleFrameRefreshFactsV0,
) -> String {
frame_refresh_stable_hash_hex(
format!(
"source={};tokens={};errors={};deps={}",
module.source,
facts.token_count,
facts.error_count,
facts.dependency_ids.join(",")
)
.as_bytes(),
)
}
fn frame_refresh_stable_hash_hex(bytes: &[u8]) -> String {
let mut hash = 0xcbf2_9ce4_8422_2325_u64;
for byte in bytes {
hash ^= u64::from(*byte);
hash = hash.wrapping_mul(0x0000_0100_0000_01b3);
}
format!("{hash:016x}")
}
fn frame_aware_refresh_enabled_from_env() -> bool {
frame_aware_refresh_enabled(
std::env::var_os("OMENA_LSP_ENABLE_FRAME_AWARE_REFRESH").is_some(),
std::env::var_os("OMENA_LSP_DISABLE_FRAME_AWARE_REFRESH").is_some(),
)
}
fn frame_aware_refresh_enabled(enable_requested: bool, disable_requested: bool) -> bool {
enable_requested && !disable_requested
}
#[cfg(test)]
mod tests {
use omena_cascade::derive_frame_for_diagnostic;
use super::*;
#[test]
fn refresh_report_selects_only_intersecting_frames() {
let frame = derive_frame_for_diagnostic(
"missing-static-class",
"d1",
vec!["file:///workspace/a.module.css".to_string()],
);
let report = refresh_diagnostics_with_frame(
&[frame],
vec!["file:///workspace/a.module.css".to_string()],
);
assert_eq!(report.schema_version, "0");
assert_eq!(report.layer_marker, "frame-rule");
assert_eq!(report.feature_gate, "OMENA_LSP_ENABLE_FRAME_AWARE_REFRESH");
assert_eq!(report.selected_diagnostic_instance_ids, vec!["d1"]);
}
#[test]
fn refresh_report_preserves_full_refresh_when_disabled() {
let selected = derive_frame_for_diagnostic(
"missing-static-class",
"selected",
vec!["file:///workspace/a.module.css".to_string()],
);
let otherwise_skipped = derive_frame_for_diagnostic(
"missing-static-class",
"otherwise-skipped",
vec!["file:///workspace/b.module.css".to_string()],
);
let report = refresh_diagnostics_with_frame_policy(
&[selected, otherwise_skipped],
vec!["file:///workspace/a.module.css".to_string()],
false,
);
assert!(!report.selective_refresh_enabled);
assert_eq!(
report.selected_diagnostic_instance_ids,
vec!["selected", "otherwise-skipped"]
);
assert!(report.skipped_diagnostic_instance_ids.is_empty());
}
#[test]
fn refresh_policy_is_positive_opt_in() {
assert!(!frame_aware_refresh_enabled(false, false));
assert!(frame_aware_refresh_enabled(true, false));
assert!(!frame_aware_refresh_enabled(true, true));
assert!(!frame_aware_refresh_enabled(false, true));
}
#[test]
fn fixed_workspace_comparison_reports_work_reduction_when_enabled() {
let frames = (0..100)
.map(|index| {
derive_frame_for_diagnostic(
"missing-static-class",
format!("d{index}"),
vec![format!("file:///workspace/module-{index}.module.css")],
)
})
.collect::<Vec<_>>();
let report = compare_frame_refresh_against_unconditional_baseline(
&frames,
vec!["file:///workspace/module-7.module.css".to_string()],
);
assert_eq!(report.schema_version, "0");
assert_eq!(report.layer_marker, "frame-rule");
assert_eq!(report.feature_gate, "OMENA_LSP_ENABLE_FRAME_AWARE_REFRESH");
assert!(!report.selective_refresh_enabled_by_default);
assert_eq!(report.diagnostic_frame_count, 100);
assert_eq!(report.unconditional_selected_count, 100);
assert_eq!(report.selective_selected_count, 1);
assert_eq!(report.skipped_diagnostic_count, 99);
assert!(report.selected_work_reduction_ratio >= 0.99);
}
#[test]
fn runtime_refresh_uses_parser_facts_and_salsa_dirty_dependencies() {
let mut runtime = FrameAwareRefreshRuntimeV0::default();
let frames = vec![
derive_frame_for_diagnostic(
"missing-static-class",
"a-diagnostic",
vec!["a".to_string()],
),
derive_frame_for_diagnostic(
"missing-static-class",
"b-diagnostic",
vec!["b".to_string()],
),
];
let initial = vec![
FrameAwareStyleModuleInputV0 {
module_id: "a".to_string(),
source: ".a { color: red; }".to_string(),
dialect: OmenaParserStyleDialect::Scss,
},
FrameAwareStyleModuleInputV0 {
module_id: "b".to_string(),
source: "@use \"a\"; .b { color: blue; }".to_string(),
dialect: OmenaParserStyleDialect::Scss,
},
];
let first = runtime.refresh_diagnostics_with_style_modules_policy(&frames, &initial, true);
assert_eq!(
first.selected_diagnostic_instance_ids,
vec!["a-diagnostic", "b-diagnostic"]
);
let changed = vec![
FrameAwareStyleModuleInputV0 {
module_id: "a".to_string(),
source: ".a { color: green; }".to_string(),
dialect: OmenaParserStyleDialect::Scss,
},
FrameAwareStyleModuleInputV0 {
module_id: "b".to_string(),
source: "@use \"a\"; .b { color: blue; }".to_string(),
dialect: OmenaParserStyleDialect::Scss,
},
];
let second = runtime.refresh_diagnostics_with_style_modules_policy(&frames, &changed, true);
assert_eq!(second.edited_module_count, 2);
assert_eq!(
second.selected_diagnostic_instance_ids,
vec!["a-diagnostic", "b-diagnostic"]
);
}
}