use std::collections::BTreeMap;
use serde::Serialize;
use crate::StyleSemanticGraphSummaryV0;
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TheoryObservationHarnessSummaryV0 {
pub schema_version: &'static str,
pub product: &'static str,
pub graph_product: &'static str,
pub selector_identity: SelectorIdentityObservationV0,
pub source_evidence: SourceEvidenceObservationV0,
pub downstream_readiness: SemanticGraphDownstreamReadinessV0,
pub coupling_boundary: SemanticCouplingBoundaryObservationV0,
pub blocking_gaps: Vec<&'static str>,
pub next_priorities: Vec<&'static str>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TheoryObservationContractV0 {
pub schema_version: &'static str,
pub product: &'static str,
pub observation_product: &'static str,
pub ready: bool,
pub publish_ready: bool,
pub selector_identity_status: &'static str,
pub source_evidence_status: &'static str,
pub downstream_readiness_status: &'static str,
pub generic_observation_count: usize,
pub cme_coupled_observation_count: usize,
pub blocking_gaps: Vec<&'static str>,
pub publish_blocking_gaps: Vec<&'static str>,
pub observation_gaps: Vec<&'static str>,
pub next_priorities: Vec<&'static str>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct SelectorIdentityObservationV0 {
pub status: &'static str,
pub observed_selector_count: usize,
pub rename_safe_selector_count: usize,
pub rewrite_blocked_selector_count: usize,
pub precise_rename_span_ready: bool,
pub rename_safe: bool,
pub blockers: Vec<&'static str>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct SourceEvidenceObservationV0 {
pub status: &'static str,
pub reference_site_count: usize,
pub editable_direct_site_count: usize,
pub expression_count: usize,
pub explainable_certainty_reason_count: usize,
pub missing_certainty_reason_count: usize,
pub certainty_reason_counts: BTreeMap<String, usize>,
pub cme_coupled: bool,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct SemanticGraphDownstreamReadinessV0 {
pub status: &'static str,
pub semantic_graph_ready: bool,
pub downstream_check_ready: bool,
pub precise_rename_ready: bool,
pub formatter_ready: bool,
pub recovery_diagnostics_observed: bool,
pub blocking_gap_count: usize,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct SemanticCouplingBoundaryObservationV0 {
pub status: &'static str,
pub generic_observation_count: usize,
pub cme_coupled_observation_count: usize,
pub generic_surfaces: Vec<&'static str>,
pub cme_coupled_surfaces: Vec<&'static str>,
pub split_recommendation: &'static str,
}
pub trait TheoryObservationHarnessInput {
fn summarize_theory_observation_harness(&self) -> TheoryObservationHarnessSummaryV0;
fn summarize_theory_observation_contract(&self) -> TheoryObservationContractV0 {
summarize_theory_observation_contract(self)
}
}
impl TheoryObservationHarnessInput for StyleSemanticGraphSummaryV0 {
fn summarize_theory_observation_harness(&self) -> TheoryObservationHarnessSummaryV0 {
summarize_style_semantic_graph_observation(self)
}
}
pub fn summarize_theory_observation_harness<T>(input: &T) -> TheoryObservationHarnessSummaryV0
where
T: TheoryObservationHarnessInput + ?Sized,
{
input.summarize_theory_observation_harness()
}
pub fn summarize_theory_observation_contract<T>(input: &T) -> TheoryObservationContractV0
where
T: TheoryObservationHarnessInput + ?Sized,
{
summarize_theory_observation_contract_from_summary(
&input.summarize_theory_observation_harness(),
)
}
fn summarize_style_semantic_graph_observation(
graph: &StyleSemanticGraphSummaryV0,
) -> TheoryObservationHarnessSummaryV0 {
let selector_identity = observe_selector_identity(graph);
let source_evidence = observe_source_evidence(graph);
let downstream_readiness = observe_downstream_readiness(graph, &selector_identity);
let coupling_boundary = observe_coupling_boundary(graph);
let mut blocking_gaps = Vec::new();
if selector_identity.status != "ready" {
blocking_gaps.push("selectorRewriteSafety");
}
if source_evidence.status != "ready" {
blocking_gaps.push("sourceEvidence");
}
if downstream_readiness.status != "ready" {
blocking_gaps.push("downstreamReadiness");
}
let next_priorities = if blocking_gaps.is_empty() {
vec!["externalCorpus", "traitDogfooding"]
} else {
blocking_gaps.clone()
};
TheoryObservationHarnessSummaryV0 {
schema_version: "0",
product: "omena-semantic.theory-observation-harness",
graph_product: graph.product,
selector_identity,
source_evidence,
downstream_readiness,
coupling_boundary,
blocking_gaps,
next_priorities,
}
}
fn summarize_theory_observation_contract_from_summary(
observation: &TheoryObservationHarnessSummaryV0,
) -> TheoryObservationContractV0 {
let publish_blocking_gaps = publish_blocking_gaps_for_observation(observation);
let observation_gaps = observation
.blocking_gaps
.iter()
.copied()
.filter(|gap| !publish_blocking_gaps.contains(gap))
.collect::<Vec<_>>();
TheoryObservationContractV0 {
schema_version: "0",
product: "omena-semantic.theory-observation-contract",
observation_product: observation.product,
ready: observation.blocking_gaps.is_empty(),
publish_ready: publish_blocking_gaps.is_empty(),
selector_identity_status: observation.selector_identity.status,
source_evidence_status: observation.source_evidence.status,
downstream_readiness_status: observation.downstream_readiness.status,
generic_observation_count: observation.coupling_boundary.generic_observation_count,
cme_coupled_observation_count: observation.coupling_boundary.cme_coupled_observation_count,
blocking_gaps: observation.blocking_gaps.clone(),
publish_blocking_gaps,
observation_gaps,
next_priorities: observation.next_priorities.clone(),
}
}
fn publish_blocking_gaps_for_observation(
observation: &TheoryObservationHarnessSummaryV0,
) -> Vec<&'static str> {
let mut gaps = Vec::new();
if observation.selector_identity.status != "ready" {
gaps.push("selectorRewriteSafety");
}
if observation.coupling_boundary.generic_observation_count == 0 {
gaps.push("genericObservationBoundary");
}
gaps
}
fn observe_selector_identity(graph: &StyleSemanticGraphSummaryV0) -> SelectorIdentityObservationV0 {
let observed_selector_count = graph.selector_identity_engine.canonical_id_count;
let rewrite_blocked_selector_count = graph
.selector_identity_engine
.rewrite_safety
.blocked_canonical_ids
.len();
let rename_safe_selector_count = graph
.selector_identity_engine
.rewrite_safety
.safe_canonical_ids
.len();
let precise_rename_span_ready = graph
.lossless_cst_contract
.consumer_readiness
.precise_rename_base_ready;
let rename_safe = observed_selector_count > 0
&& rewrite_blocked_selector_count == 0
&& precise_rename_span_ready;
SelectorIdentityObservationV0 {
status: if observed_selector_count == 0 {
"gap"
} else if rename_safe {
"ready"
} else {
"partial"
},
observed_selector_count,
rename_safe_selector_count,
rewrite_blocked_selector_count,
precise_rename_span_ready,
rename_safe,
blockers: graph
.selector_identity_engine
.rewrite_safety
.blockers
.clone(),
}
}
fn observe_source_evidence(graph: &StyleSemanticGraphSummaryV0) -> SourceEvidenceObservationV0 {
let evidence = &graph.source_input_evidence;
let expression_count = evidence.certainty_reason.expression_count;
let missing_certainty_reason_count = evidence.certainty_reason.missing_reason_count;
let explainable_certainty_reason_count =
expression_count.saturating_sub(missing_certainty_reason_count);
let source_observed =
evidence.reference_site_identity.reference_site_count > 0 || expression_count > 0;
let source_ready = evidence.reference_site_identity.status == "ready"
&& evidence.certainty_reason.status == "ready"
&& evidence.binding_origin.status == "ready"
&& evidence.style_module_edge.status == "ready"
&& evidence.value_domain_explanation.status == "ready";
SourceEvidenceObservationV0 {
status: if source_ready {
"ready"
} else if source_observed {
"partial"
} else {
"gap"
},
reference_site_count: evidence.reference_site_identity.reference_site_count,
editable_direct_site_count: evidence.reference_site_identity.editable_direct_site_count,
expression_count,
explainable_certainty_reason_count,
missing_certainty_reason_count,
certainty_reason_counts: evidence.certainty_reason.reason_counts.clone(),
cme_coupled: true,
}
}
fn observe_downstream_readiness(
graph: &StyleSemanticGraphSummaryV0,
selector_identity: &SelectorIdentityObservationV0,
) -> SemanticGraphDownstreamReadinessV0 {
let semantic_graph_ready = graph.product == "omena-semantic.style-semantic-graph"
&& graph.promotion_evidence.blocking_gaps.is_empty()
&& graph.selector_identity_engine.canonical_id_count > 0
&& graph
.lossless_cst_contract
.span_invariants
.byte_span_contract_ready;
let downstream_check_ready = semantic_graph_ready && selector_identity.status != "gap";
let precise_rename_ready = downstream_check_ready && selector_identity.rename_safe;
let formatter_ready = graph
.lossless_cst_contract
.consumer_readiness
.formatter_base_ready;
SemanticGraphDownstreamReadinessV0 {
status: if downstream_check_ready && precise_rename_ready {
"ready"
} else if semantic_graph_ready {
"partial"
} else {
"gap"
},
semantic_graph_ready,
downstream_check_ready,
precise_rename_ready,
formatter_ready,
recovery_diagnostics_observed: graph
.lossless_cst_contract
.consumer_readiness
.recovery_diagnostics_observed,
blocking_gap_count: graph.promotion_evidence.blocking_gaps.len(),
}
}
fn observe_coupling_boundary(
graph: &StyleSemanticGraphSummaryV0,
) -> SemanticCouplingBoundaryObservationV0 {
let generic_surfaces = vec![
"parserSemanticFacts",
"selectorIdentity",
"losslessCstContract",
];
let cme_coupled_surfaces = vec!["sourceInputEvidence", "promotionEvidenceWithSourceInput"];
let cme_coupled_observation_count = if graph.source_input_evidence.input_version.is_empty() {
0
} else {
cme_coupled_surfaces.len()
};
let split_recommendation = if cme_coupled_observation_count == 0 {
"keep-integrated-source-gap"
} else {
"keep-integrated-observe-boundary"
};
SemanticCouplingBoundaryObservationV0 {
status: "ready",
generic_observation_count: generic_surfaces.len(),
cme_coupled_observation_count,
generic_surfaces,
cme_coupled_surfaces,
split_recommendation,
}
}