use crate::diagnostic::{CompatDiagnostic, DiagnosticSeverity};
use crate::hash::{blake3_string, canonical_json};
use serde::{Deserialize, Serialize};
use std::collections::BTreeSet;
use std::fmt::{Display, Write as _};
pub const DOCTOR_SCHEMA: &str = "https://chatmangpt.com/ns/wasm4pm-compat/doctor/v1";
pub const DOCTOR_SCHEMA_VERSION: u32 = 1;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum DoctorProfile {
Core,
Boundary,
Interop,
Graduation,
Vision2030,
}
impl DoctorProfile {
pub const ALL: [Self; 5] = [
Self::Core,
Self::Boundary,
Self::Interop,
Self::Graduation,
Self::Vision2030,
];
pub const fn as_str(self) -> &'static str {
match self {
Self::Core => "core",
Self::Boundary => "boundary",
Self::Interop => "interop",
Self::Graduation => "graduation",
Self::Vision2030 => "vision2030",
}
}
pub fn parse(value: &str) -> Option<Self> {
match value.trim().to_ascii_lowercase().as_str() {
"core" => Some(Self::Core),
"boundary" | "default" => Some(Self::Boundary),
"interop" | "formats" => Some(Self::Interop),
"graduation" | "wasm4pm" => Some(Self::Graduation),
"vision2030" | "vision-2030" | "2030" | "all" => Some(Self::Vision2030),
_ => None,
}
}
fn requirements(self) -> &'static [Capability] {
const CORE: &[Capability] = &[
Capability::TypedEvidence,
Capability::NamedRefusals,
Capability::Diagnostics,
];
const BOUNDARY: &[Capability] = &[
Capability::TypedEvidence,
Capability::NamedRefusals,
Capability::Diagnostics,
Capability::ReceiptShapes,
Capability::DeterministicDigests,
Capability::Dfcm,
Capability::Doctor,
];
const INTEROP: &[Capability] = &[
Capability::TypedEvidence,
Capability::NamedRefusals,
Capability::Diagnostics,
Capability::ReceiptShapes,
Capability::DeterministicDigests,
Capability::Dfcm,
Capability::Doctor,
Capability::Formats,
];
const GRADUATION: &[Capability] = &[
Capability::TypedEvidence,
Capability::NamedRefusals,
Capability::Diagnostics,
Capability::ReceiptShapes,
Capability::DeterministicDigests,
Capability::Dfcm,
Capability::Doctor,
Capability::GraduationBridge,
];
const VISION_2030: &[Capability] = &[
Capability::TypedEvidence,
Capability::NamedRefusals,
Capability::Diagnostics,
Capability::ReceiptShapes,
Capability::DeterministicDigests,
Capability::Dfcm,
Capability::Doctor,
Capability::Formats,
Capability::StrictBoundary,
Capability::GraduationBridge,
Capability::EngineExecution,
Capability::StandingAuthority,
];
match self {
Self::Core => CORE,
Self::Boundary => BOUNDARY,
Self::Interop => INTEROP,
Self::Graduation => GRADUATION,
Self::Vision2030 => VISION_2030,
}
}
}
impl Display for DoctorProfile {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum CapabilityOwner {
Compat,
Wasm4pm,
ExternalVerifier,
}
impl CapabilityOwner {
pub const fn as_str(self) -> &'static str {
match self {
Self::Compat => "wasm4pm-compat",
Self::Wasm4pm => "wasm4pm",
Self::ExternalVerifier => "external-verifier",
}
}
}
impl Display for CapabilityOwner {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Capability {
TypedEvidence,
NamedRefusals,
Diagnostics,
ReceiptShapes,
DeterministicDigests,
Dfcm,
Doctor,
Formats,
StrictBoundary,
GraduationBridge,
EngineExecution,
StandingAuthority,
}
impl Capability {
pub const ALL: [Self; 12] = [
Self::TypedEvidence,
Self::NamedRefusals,
Self::Diagnostics,
Self::ReceiptShapes,
Self::DeterministicDigests,
Self::Dfcm,
Self::Doctor,
Self::Formats,
Self::StrictBoundary,
Self::GraduationBridge,
Self::EngineExecution,
Self::StandingAuthority,
];
pub const fn code(self) -> &'static str {
match self {
Self::TypedEvidence => "typed_evidence",
Self::NamedRefusals => "named_refusals",
Self::Diagnostics => "diagnostics",
Self::ReceiptShapes => "receipt_shapes",
Self::DeterministicDigests => "deterministic_digests",
Self::Dfcm => "dfcm",
Self::Doctor => "doctor",
Self::Formats => "formats",
Self::StrictBoundary => "strict_boundary",
Self::GraduationBridge => "graduation_bridge",
Self::EngineExecution => "engine_execution",
Self::StandingAuthority => "standing_authority",
}
}
pub const fn summary(self) -> &'static str {
match self {
Self::TypedEvidence => "witness-bound typestate evidence",
Self::NamedRefusals => "specific typed refusal laws",
Self::Diagnostics => "diagnostic and repair vocabulary",
Self::ReceiptShapes => "receipt and replay-hint shapes",
Self::DeterministicDigests => "canonical JSON and BLAKE3 identities",
Self::Dfcm => "combinatorial coverage matrices",
Self::Doctor => "deterministic doctor and route planner",
Self::Formats => "import, export, projection, and round-trip contracts",
Self::StrictBoundary => "strict admission and refusal surfaces",
Self::GraduationBridge => "structural graduation candidates",
Self::EngineExecution => "discovery, conformance, replay, and optimization",
Self::StandingAuthority => "exact-tree external standing judgment",
}
}
pub const fn owner(self) -> CapabilityOwner {
match self {
Self::EngineExecution => CapabilityOwner::Wasm4pm,
Self::StandingAuthority => CapabilityOwner::ExternalVerifier,
_ => CapabilityOwner::Compat,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum CapabilityState {
Available,
Blocked,
Routed,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CapabilityObservation {
pub capability: Capability,
pub code: String,
pub owner: CapabilityOwner,
pub state: CapabilityState,
pub required_feature: Option<String>,
pub reason: String,
}
impl CapabilityObservation {
fn available(capability: Capability) -> Self {
Self {
capability,
code: capability.code().to_string(),
owner: capability.owner(),
state: CapabilityState::Available,
required_feature: None,
reason: format!("{} is present in the compat core", capability.summary()),
}
}
fn feature(capability: Capability, feature: &str, enabled: bool) -> Self {
let state = if enabled {
CapabilityState::Available
} else {
CapabilityState::Blocked
};
let reason = if enabled {
format!("Cargo feature `{feature}` is enabled")
} else {
format!("Cargo feature `{feature}` is disabled")
};
Self {
capability,
code: capability.code().to_string(),
owner: CapabilityOwner::Compat,
state,
required_feature: Some(feature.to_string()),
reason,
}
}
fn routed(capability: Capability, reason: &str) -> Self {
Self {
capability,
code: capability.code().to_string(),
owner: capability.owner(),
state: CapabilityState::Routed,
required_feature: None,
reason: reason.to_string(),
}
}
}
pub fn capability_snapshot() -> Vec<CapabilityObservation> {
vec![
CapabilityObservation::available(Capability::TypedEvidence),
CapabilityObservation::available(Capability::NamedRefusals),
CapabilityObservation::available(Capability::Diagnostics),
CapabilityObservation::available(Capability::ReceiptShapes),
CapabilityObservation::available(Capability::DeterministicDigests),
CapabilityObservation::available(Capability::Dfcm),
CapabilityObservation::available(Capability::Doctor),
CapabilityObservation::feature(Capability::Formats, "formats", cfg!(feature = "formats")),
CapabilityObservation::feature(
Capability::StrictBoundary,
"strict",
cfg!(feature = "strict"),
),
CapabilityObservation::feature(
Capability::GraduationBridge,
"wasm4pm",
cfg!(feature = "wasm4pm"),
),
CapabilityObservation::routed(
Capability::EngineExecution,
"active execution is owned by wasm4pm; compat only prepares graduation candidates",
),
CapabilityObservation::routed(
Capability::StandingAuthority,
"ALIVE is awarded only by an exact-tree external verifier",
),
]
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum DoctorCheckState {
Pass,
Advisory,
Blocked,
Unsupported,
Refused,
}
impl DoctorCheckState {
pub const fn as_str(self) -> &'static str {
match self {
Self::Pass => "PASS",
Self::Advisory => "ADVISORY",
Self::Blocked => "BLOCKED",
Self::Unsupported => "UNSUPPORTED",
Self::Refused => "REFUSED",
}
}
}
impl Display for DoctorCheckState {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum DoctorStanding {
Unknown,
PartialAlive,
Blocked,
BuildBroken,
Unsupported,
}
impl DoctorStanding {
pub const fn as_str(self) -> &'static str {
match self {
Self::Unknown => "UNKNOWN",
Self::PartialAlive => "PARTIAL_ALIVE",
Self::Blocked => "BLOCKED",
Self::BuildBroken => "BUILD_BROKEN",
Self::Unsupported => "UNSUPPORTED",
}
}
}
impl Display for DoctorStanding {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct RepairAction {
pub code: String,
pub owner: CapabilityOwner,
pub summary: String,
pub command: Option<String>,
pub reversible: bool,
}
impl RepairAction {
fn enable_feature(feature: &str) -> Self {
Self {
code: format!("ENABLE_FEATURE_{}", feature.to_ascii_uppercase()),
owner: CapabilityOwner::Compat,
summary: format!("enable Cargo feature `{feature}` for this consumer"),
command: Some(format!(
"cargo run --features {feature} --bin wasm4pm-compat -- doctor"
)),
reversible: true,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct DoctorCheck {
pub code: String,
pub capability: Option<Capability>,
pub state: DoctorCheckState,
pub summary: String,
pub detail: String,
pub repair: Option<RepairAction>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct DoctorReport {
pub schema: String,
pub schema_version: u32,
pub crate_name: String,
pub crate_version: String,
pub profile: DoctorProfile,
pub standing: DoctorStanding,
pub checks: Vec<DoctorCheck>,
pub capabilities: Vec<CapabilityObservation>,
pub repairs: Vec<RepairAction>,
}
impl DoctorReport {
pub fn canonical_json(&self) -> Result<String, serde_json::Error> {
canonical_json(self)
}
pub fn fingerprint(&self) -> Result<String, serde_json::Error> {
Ok(blake3_string(&self.canonical_json()?))
}
pub fn is_blocked(&self) -> bool {
self.checks
.iter()
.any(|check| check.state == DoctorCheckState::Blocked)
}
pub const fn exit_code(&self) -> u8 {
match self.standing {
DoctorStanding::PartialAlive => 0,
DoctorStanding::Unknown => 1,
DoctorStanding::Blocked => 2,
DoctorStanding::BuildBroken => 3,
DoctorStanding::Unsupported => 4,
}
}
pub fn render_text(&self) -> String {
let mut output = String::new();
writeln!(
&mut output,
"wasm4pm-compat doctor {} ({})",
self.profile, self.crate_version
)
.expect("writing to String cannot fail");
writeln!(&mut output, "standing: {}", self.standing)
.expect("writing to String cannot fail");
for check in &self.checks {
writeln!(
&mut output,
"[{}] {} — {}",
check.state, check.code, check.summary
)
.expect("writing to String cannot fail");
writeln!(&mut output, " {}", check.detail).expect("writing to String cannot fail");
}
if !self.repairs.is_empty() {
output.push_str("repairs:\n");
for repair in &self.repairs {
writeln!(&mut output, "- {}: {}", repair.code, repair.summary)
.expect("writing to String cannot fail");
if let Some(command) = &repair.command {
writeln!(&mut output, " {}", command).expect("writing to String cannot fail");
}
}
}
output
}
}
#[derive(Debug, Default, Clone, Copy)]
pub struct CompatDoctor;
impl CompatDoctor {
pub fn run(profile: DoctorProfile) -> DoctorReport {
let capabilities = capability_snapshot();
let mut checks = Vec::new();
for capability in profile.requirements() {
let observation = capabilities
.iter()
.find(|candidate| candidate.capability == *capability);
match observation {
Some(observation) => checks.push(check_from_observation(observation)),
None => checks.push(DoctorCheck {
code: format!(
"CAPABILITY_{}_UNMODELED",
capability.code().to_ascii_uppercase()
),
capability: Some(*capability),
state: DoctorCheckState::Unsupported,
summary: format!("{} is not modeled", capability.summary()),
detail: "the bounded doctor has no observation for this capability".to_string(),
repair: None,
}),
}
}
checks.push(DoctorCheck {
code: "COMPAT_DOCTOR_NO_ALIVE_AUTHORITY".to_string(),
capability: Some(Capability::StandingAuthority),
state: DoctorCheckState::Advisory,
summary: "crown standing remains external".to_string(),
detail: "the doctor can issue PARTIAL_ALIVE but cannot award ALIVE".to_string(),
repair: None,
});
checks.push(DoctorCheck {
code: "COMPAT_DOCTOR_ZERO_ACTUATION".to_string(),
capability: Some(Capability::Doctor),
state: DoctorCheckState::Pass,
summary: "doctor performs no process or repository actuation".to_string(),
detail: "all outputs are inert reports, route decisions, and reversible repair plans"
.to_string(),
repair: None,
});
let standing = standing_from_checks(&checks);
let repairs = collect_repairs(&checks);
DoctorReport {
schema: DOCTOR_SCHEMA.to_string(),
schema_version: DOCTOR_SCHEMA_VERSION,
crate_name: env!("CARGO_PKG_NAME").to_string(),
crate_version: env!("CARGO_PKG_VERSION").to_string(),
profile,
standing,
checks,
capabilities,
repairs,
}
}
pub fn plan(intents: impl IntoIterator<Item = Intent>) -> RoutePlan {
RoutePlan::new(intents)
}
}
fn check_from_observation(observation: &CapabilityObservation) -> DoctorCheck {
let (state, repair) = match observation.state {
CapabilityState::Available => (DoctorCheckState::Pass, None),
CapabilityState::Blocked => (
DoctorCheckState::Blocked,
observation
.required_feature
.as_deref()
.map(RepairAction::enable_feature),
),
CapabilityState::Routed => (DoctorCheckState::Advisory, None),
};
DoctorCheck {
code: format!("CAPABILITY_{}", observation.code.to_ascii_uppercase()),
capability: Some(observation.capability),
state,
summary: observation.capability.summary().to_string(),
detail: observation.reason.clone(),
repair,
}
}
fn standing_from_checks(checks: &[DoctorCheck]) -> DoctorStanding {
if checks.is_empty() {
return DoctorStanding::Unknown;
}
if checks
.iter()
.any(|check| check.state == DoctorCheckState::Unsupported)
{
return DoctorStanding::Unsupported;
}
if checks.iter().any(|check| {
matches!(
check.state,
DoctorCheckState::Blocked | DoctorCheckState::Refused
)
}) {
return DoctorStanding::Blocked;
}
DoctorStanding::PartialAlive
}
fn collect_repairs(checks: &[DoctorCheck]) -> Vec<RepairAction> {
let mut seen = BTreeSet::new();
let mut repairs = Vec::new();
for repair in checks.iter().filter_map(|check| check.repair.clone()) {
if seen.insert(repair.code.clone()) {
repairs.push(repair);
}
}
repairs
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Intent {
Admit,
StrictAdmit,
Import,
Project,
Export,
Receipt,
Diagnose,
Graduate,
Discover,
Conformance,
Replay,
Optimize,
VerifyStanding,
}
impl Intent {
pub const fn as_str(self) -> &'static str {
match self {
Self::Admit => "admit",
Self::StrictAdmit => "strict_admit",
Self::Import => "import",
Self::Project => "project",
Self::Export => "export",
Self::Receipt => "receipt",
Self::Diagnose => "diagnose",
Self::Graduate => "graduate",
Self::Discover => "discover",
Self::Conformance => "conformance",
Self::Replay => "replay",
Self::Optimize => "optimize",
Self::VerifyStanding => "verify_standing",
}
}
pub fn parse(value: &str) -> Option<Self> {
match value.trim().to_ascii_lowercase().replace('-', "_").as_str() {
"admit" | "admission" => Some(Self::Admit),
"strict" | "strict_admit" | "strict_admission" => Some(Self::StrictAdmit),
"import" => Some(Self::Import),
"project" | "projection" => Some(Self::Project),
"export" => Some(Self::Export),
"receipt" | "receipt_shape" => Some(Self::Receipt),
"diagnose" | "doctor" => Some(Self::Diagnose),
"graduate" | "graduation" => Some(Self::Graduate),
"discover" | "discovery" => Some(Self::Discover),
"conformance" | "conform" => Some(Self::Conformance),
"replay" => Some(Self::Replay),
"optimize" | "optimise" | "plan" => Some(Self::Optimize),
"verify_standing" | "standing" | "alive" => Some(Self::VerifyStanding),
_ => None,
}
}
}
impl Display for Intent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum RouteTarget {
Compat,
Wasm4pm,
ExternalVerifier,
}
impl From<RouteTarget> for CapabilityOwner {
fn from(value: RouteTarget) -> Self {
match value {
RouteTarget::Compat => Self::Compat,
RouteTarget::Wasm4pm => Self::Wasm4pm,
RouteTarget::ExternalVerifier => Self::ExternalVerifier,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum RouteState {
Admitted,
Blocked,
Routed,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct RouteDecision {
pub intent: Intent,
pub target: RouteTarget,
pub state: RouteState,
pub reason: String,
pub required_feature: Option<String>,
pub repair: Option<RepairAction>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct RoutePlan {
pub schema: String,
pub standing: DoctorStanding,
pub decisions: Vec<RouteDecision>,
pub repairs: Vec<RepairAction>,
}
impl RoutePlan {
fn new(intents: impl IntoIterator<Item = Intent>) -> Self {
let decisions: Vec<_> = intents.into_iter().map(route_intent).collect();
let standing = if decisions.is_empty() {
DoctorStanding::Unknown
} else if decisions
.iter()
.any(|decision| decision.state == RouteState::Blocked)
{
DoctorStanding::Blocked
} else {
DoctorStanding::PartialAlive
};
let mut seen = BTreeSet::new();
let mut repairs = Vec::new();
for repair in decisions
.iter()
.filter_map(|decision| decision.repair.clone())
{
if seen.insert(repair.code.clone()) {
repairs.push(repair);
}
}
Self {
schema: format!("{DOCTOR_SCHEMA}/route-plan"),
standing,
decisions,
repairs,
}
}
pub fn canonical_json(&self) -> Result<String, serde_json::Error> {
canonical_json(self)
}
pub fn fingerprint(&self) -> Result<String, serde_json::Error> {
Ok(blake3_string(&self.canonical_json()?))
}
pub fn render_text(&self) -> String {
let mut output = format!("route standing: {}\n", self.standing);
for decision in &self.decisions {
writeln!(
&mut output,
"[{:?}] {} -> {:?}: {}",
decision.state, decision.intent, decision.target, decision.reason
)
.expect("writing to String cannot fail");
}
if !self.repairs.is_empty() {
output.push_str("repairs:\n");
for repair in &self.repairs {
writeln!(&mut output, "- {}: {}", repair.code, repair.summary)
.expect("writing to String cannot fail");
}
}
output
}
}
fn route_intent(intent: Intent) -> RouteDecision {
match intent {
Intent::Admit | Intent::Receipt | Intent::Diagnose => RouteDecision {
intent,
target: RouteTarget::Compat,
state: RouteState::Admitted,
reason: "intent is structure-only and belongs in the compatibility court".to_string(),
required_feature: None,
repair: None,
},
Intent::StrictAdmit => feature_route(intent, RouteTarget::Compat, "strict"),
Intent::Import | Intent::Project | Intent::Export => {
feature_route(intent, RouteTarget::Compat, "formats")
}
Intent::Graduate => feature_route(intent, RouteTarget::Compat, "wasm4pm"),
Intent::Discover | Intent::Conformance | Intent::Replay | Intent::Optimize => {
if cfg!(feature = "wasm4pm") {
RouteDecision {
intent,
target: RouteTarget::Wasm4pm,
state: RouteState::Routed,
reason: "active execution is fenced out of compat and routed through the graduation bridge"
.to_string(),
required_feature: Some("wasm4pm".to_string()),
repair: None,
}
} else {
RouteDecision {
intent,
target: RouteTarget::Wasm4pm,
state: RouteState::Blocked,
reason: "the lawful engine route exists, but the `wasm4pm` graduation feature is disabled"
.to_string(),
required_feature: Some("wasm4pm".to_string()),
repair: Some(RepairAction::enable_feature("wasm4pm")),
}
}
}
Intent::VerifyStanding => RouteDecision {
intent,
target: RouteTarget::ExternalVerifier,
state: RouteState::Routed,
reason: "exact-tree standing is external; compat cannot self-promote to ALIVE"
.to_string(),
required_feature: None,
repair: None,
},
}
}
fn feature_route(intent: Intent, target: RouteTarget, feature: &str) -> RouteDecision {
#[allow(clippy::match_like_matches_macro)]
let enabled = match feature {
"formats" => cfg!(feature = "formats"),
"strict" => cfg!(feature = "strict"),
"wasm4pm" => cfg!(feature = "wasm4pm"),
_ => false,
};
if enabled {
RouteDecision {
intent,
target,
state: RouteState::Admitted,
reason: format!("Cargo feature `{feature}` admits this structural route"),
required_feature: Some(feature.to_string()),
repair: None,
}
} else {
RouteDecision {
intent,
target,
state: RouteState::Blocked,
reason: format!("Cargo feature `{feature}` is required for this structural route"),
required_feature: Some(feature.to_string()),
repair: Some(RepairAction::enable_feature(feature)),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct DiagnosticCatalogEntry {
pub code: String,
pub name: String,
pub severity: String,
pub message: String,
pub repair: String,
}
pub fn diagnostic_catalog() -> Vec<DiagnosticCatalogEntry> {
CompatDiagnostic::ALL
.into_iter()
.map(|diagnostic| DiagnosticCatalogEntry {
code: diagnostic.code().to_string(),
name: diagnostic.name().to_string(),
severity: diagnostic.severity().to_string(),
message: diagnostic.message().to_string(),
repair: diagnostic.repair().to_string(),
})
.collect()
}
pub fn explain_diagnostic(value: &str) -> Option<DiagnosticCatalogEntry> {
CompatDiagnostic::from_code(value).map(|diagnostic| DiagnosticCatalogEntry {
code: diagnostic.code().to_string(),
name: diagnostic.name().to_string(),
severity: diagnostic.severity().to_string(),
message: diagnostic.message().to_string(),
repair: diagnostic.repair().to_string(),
})
}
pub const fn check_state_for_severity(severity: DiagnosticSeverity) -> DoctorCheckState {
match severity {
DiagnosticSeverity::Error => DoctorCheckState::Refused,
DiagnosticSeverity::Warning => DoctorCheckState::Blocked,
DiagnosticSeverity::Info => DoctorCheckState::Advisory,
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::BTreeSet;
#[test]
fn capability_snapshot_is_complete_and_unique() {
let snapshot = capability_snapshot();
assert_eq!(snapshot.len(), Capability::ALL.len());
let unique: BTreeSet<_> = snapshot.iter().map(|item| item.code.as_str()).collect();
assert_eq!(unique.len(), snapshot.len());
}
#[test]
fn core_report_is_bounded_partial_alive() {
let report = CompatDoctor::run(DoctorProfile::Core);
assert_eq!(report.standing, DoctorStanding::PartialAlive);
assert!(!report.is_blocked());
}
#[test]
fn vision_profile_tracks_feature_closure() {
let report = CompatDoctor::run(DoctorProfile::Vision2030);
let all_features =
cfg!(feature = "formats") && cfg!(feature = "strict") && cfg!(feature = "wasm4pm");
assert_eq!(
report.standing,
if all_features {
DoctorStanding::PartialAlive
} else {
DoctorStanding::Blocked
}
);
}
#[test]
fn fingerprint_is_deterministic_lowercase_blake3() {
let report = CompatDoctor::run(DoctorProfile::Boundary);
let first = report.fingerprint().unwrap();
let second = report.fingerprint().unwrap();
assert_eq!(first, second);
assert_eq!(first.len(), 64);
assert!(first
.chars()
.all(|ch| ch.is_ascii_digit() || ('a'..='f').contains(&ch)));
}
#[test]
fn engine_intents_never_route_to_compat() {
let plan = CompatDoctor::plan([
Intent::Discover,
Intent::Conformance,
Intent::Replay,
Intent::Optimize,
]);
assert!(plan
.decisions
.iter()
.all(|decision| decision.target == RouteTarget::Wasm4pm));
}
#[test]
fn standing_verification_is_always_external() {
let plan = CompatDoctor::plan([Intent::VerifyStanding]);
assert_eq!(plan.decisions.len(), 1);
assert_eq!(plan.decisions[0].target, RouteTarget::ExternalVerifier);
assert_eq!(plan.decisions[0].state, RouteState::Routed);
}
#[test]
fn missing_feature_produces_one_reversible_repair() {
let intent = if cfg!(feature = "strict") {
Intent::Graduate
} else {
Intent::StrictAdmit
};
let plan = CompatDoctor::plan([intent]);
if plan.standing == DoctorStanding::Blocked {
assert_eq!(plan.repairs.len(), 1);
assert!(plan.repairs[0].reversible);
}
}
#[test]
fn diagnostic_catalog_is_unique_and_resolvable() {
let catalog = diagnostic_catalog();
let unique: BTreeSet<_> = catalog.iter().map(|item| item.code.as_str()).collect();
assert_eq!(catalog.len(), unique.len());
let first = &catalog[0];
assert_eq!(explain_diagnostic(&first.code), Some(first.clone()));
assert_eq!(explain_diagnostic(&first.name), Some(first.clone()));
}
#[test]
fn route_plan_canonicalization_replays() {
let first = CompatDoctor::plan([Intent::Admit, Intent::VerifyStanding]);
let second = CompatDoctor::plan([Intent::Admit, Intent::VerifyStanding]);
assert_eq!(
first.canonical_json().unwrap(),
second.canonical_json().unwrap()
);
assert_eq!(first.fingerprint().unwrap(), second.fingerprint().unwrap());
}
}