use std::collections::HashSet;
use std::fs;
use std::path::{Path, PathBuf};
use serde::Deserialize;
use thiserror::Error;
pub const ALLOWED_CATEGORIES: &[&str] = &[
"python_namespace",
"cli_option",
"protocol",
"cipher",
"composition",
"process",
"failure",
];
pub const ALLOWED_STATUSES: &[&str] = &[
"gap",
"drop_in",
"structural",
"known_upstream_defect",
"platform_constraint",
"not_applicable",
"intentional_non_parity",
];
pub const ALLOWED_COMPARATORS: &[&str] = &[
"async_callable_signature",
"module_existence",
"constant_value",
"enum_membership",
"method_signature",
"property_existence",
"class_hierarchy",
"cli_flag_parse",
"cli_flag_rejection",
"protocol_wire",
"cipher_roundtrip",
"cipher_kat",
"process_lifecycle",
"failure_class",
"composition_validity",
"composition_rejection",
];
pub const ALLOWED_OWNERS: &[&str] = &["track-a", "track-b", "track-c"];
pub const ALLOWED_MILESTONES: &[&str] = &["A", "B", "C", "D", "E", "F"];
pub const ALLOWED_EVIDENCE_LEVELS: &[&str] = &[
"paired_oracle",
"bidirectional_interop",
"oracle_only_baseline",
"candidate_only",
"structural_only",
"none",
];
pub const ALLOWED_IMPLEMENTATION_STATES: &[&str] =
&["functional", "structural", "partial", "absent"];
pub const ALLOWED_CERTIFICATION_SCOPES: &[&str] =
&["structural", "behavioral", "interop", "process", "platform"];
const MILESTONE_ORDER: &[&str] = &["A", "B", "C", "D", "E", "F"];
const CURRENT_MILESTONE: &str = "C";
const TERMINAL_STATUSES: &[&str] = &[
"drop_in",
"not_applicable",
"known_upstream_defect",
"platform_constraint",
"intentional_non_parity",
"structural",
];
#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
pub struct StrictManifestMeta {
pub manifest_version: String,
pub pproxy_version: String,
pub schema: String,
#[serde(default)]
pub policy_ref: String,
#[serde(default)]
pub oracle_ref: String,
#[serde(default)]
pub closure_through: String,
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
pub struct StrictRecord {
pub id: String,
pub category: String,
#[serde(default)]
pub kind: String,
#[serde(default)]
pub module: String,
#[serde(default)]
pub name: String,
#[serde(default)]
pub oracle_probe: String,
#[serde(default)]
pub candidate_probe: String,
#[serde(default)]
pub comparator: String,
pub status: String,
#[serde(default)]
pub owner: String,
#[serde(default)]
pub milestone: String,
#[serde(default)]
pub platforms: Vec<String>,
#[serde(default)]
pub python_versions: Vec<String>,
#[serde(default)]
pub depends_on: Vec<String>,
#[serde(default)]
pub test_refs: Vec<String>,
#[serde(default)]
pub evidence_refs: Vec<String>,
#[serde(default)]
pub notes: String,
#[serde(default)]
pub evidence_level: String,
#[serde(default)]
pub implementation_state: String,
#[serde(default = "default_certification_scope")]
pub certification_scope: String,
#[serde(default = "default_closure_required")]
pub closure_required: bool,
#[serde(default)]
pub behavior_record: Option<String>,
#[serde(default)]
pub inventory_only: bool,
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
pub struct StrictManifest {
pub meta: StrictManifestMeta,
pub record: Vec<StrictRecord>,
}
#[derive(Debug, Clone, Error, PartialEq, Eq)]
pub enum StrictValidationError {
#[error("TOML parse error: {message}")]
TomlParse { message: String },
#[error("file I/O error: {message}")]
Io { message: String },
#[error("unknown category \"{value}\" (valid: {allowed:?})")]
UnknownCategory { value: String, allowed: Vec<String> },
#[error("unknown status \"{value}\" (valid: {allowed:?})")]
UnknownStatus { value: String, allowed: Vec<String> },
#[error("unknown comparator \"{value}\" (valid: {allowed:?})")]
UnknownComparator { value: String, allowed: Vec<String> },
#[error("unknown owner \"{value}\" (valid: {allowed:?})")]
UnknownOwner { value: String, allowed: Vec<String> },
#[error("unknown milestone \"{value}\" (valid: {allowed:?})")]
UnknownMilestone { value: String, allowed: Vec<String> },
#[error("duplicate record id: \"{id}\"")]
DuplicateId { id: String },
#[error("record has empty id")]
EmptyId,
#[error("drop_in record \"{id}\" has empty evidence_refs and test_refs")]
DropInWithoutEvidence { id: String },
#[error("drop_in record \"{id}\" has empty oracle_probe")]
DropInWithoutOracleProbe { id: String },
#[error(
"record \"{id}\" has non-terminal status \"{status}\" at milestone \"{milestone}\" \
(at or below current milestone {current})"
)]
UnresolvedProgress {
id: String,
status: String,
milestone: String,
current: String,
},
#[error(
"drop_in record \"{id}\" has evidence_level \"{evidence_level}\" \
(must be paired_oracle or bidirectional_interop)"
)]
DropInRequiresStrongEvidence { id: String, evidence_level: String },
#[error(
"drop_in record \"{id}\" with comparator \"{comparator}\" has \
evidence_level \"{evidence_level}\" (must not be structural_only or none)"
)]
StructuralComparatorDropInRequiresEvidence {
id: String,
comparator: String,
evidence_level: String,
},
#[error(
"record \"{id}\" has evidence_level \"structural_only\" but status \"drop_in\" \
(structural_only evidence is incompatible with drop_in)"
)]
StructuralOnlyIncompatibleWithDropIn { id: String },
#[error(
"record \"{id}\" has status \"drop_in\" with structural comparator \"{comparator}\" \
but certification_scope is \"behavioral\" (structural evidence cannot certify behavior)"
)]
StructuralComparatorBehavioralScopeMismatch { id: String, comparator: String },
#[error(
"record \"{id}\" has closure_required = true but empty evidence_refs \
(closure-required records must have evidence)"
)]
ClosureRequiredWithoutEvidence { id: String },
#[error(
"record \"{id}\" has certification_scope = \"structural\" but missing behavior_record \
(structural records must reference a behavior record)"
)]
StructuralMissingBehaviorRecord { id: String },
#[error("unknown certification_scope \"{value}\" (valid: {allowed:?})")]
UnknownCertificationScope { value: String, allowed: Vec<String> },
#[error("unknown evidence_level \"{value}\" (valid: {allowed:?})")]
UnknownEvidenceLevel { value: String, allowed: Vec<String> },
#[error("unknown implementation_state \"{value}\" (valid: {allowed:?})")]
UnknownImplementationState { value: String, allowed: Vec<String> },
}
#[derive(Debug, Clone, Error, PartialEq, Eq)]
#[error("{errors:#?}")]
pub struct StrictValidationErrors {
pub errors: Vec<StrictValidationError>,
}
impl StrictValidationErrors {
pub fn new() -> Self {
Self { errors: Vec::new() }
}
pub fn push(&mut self, err: StrictValidationError) {
self.errors.push(err);
}
pub fn is_empty(&self) -> bool {
self.errors.is_empty()
}
pub fn len(&self) -> usize {
self.errors.len()
}
}
impl Default for StrictValidationErrors {
fn default() -> Self {
Self::new()
}
}
fn default_certification_scope() -> String {
"behavioral".to_string()
}
fn default_closure_required() -> bool {
true
}
fn milestone_index(milestone: &str) -> Option<usize> {
MILESTONE_ORDER.iter().position(|&m| m == milestone)
}
pub fn find_strict_manifest_path() -> Option<PathBuf> {
if let Ok(manifest_dir) = std::env::var("CARGO_MANIFEST_DIR") {
let candidate = PathBuf::from(&manifest_dir)
.join("../../docs/parity/pproxy_2_7_9_strict_manifest.toml");
if candidate.exists() {
return Some(candidate);
}
}
let cwd = std::env::current_dir().ok()?;
let mut dir = cwd.as_path();
loop {
let candidate = dir.join("docs/parity/pproxy_2_7_9_strict_manifest.toml");
if candidate.exists() {
return Some(candidate);
}
dir = dir.parent()?;
}
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
pub struct OracleHashes {
pub package: OracleHashPackage,
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
pub struct OracleHashPackage {
pub version: String,
pub source: String,
pub sha256_sdist: Option<String>,
pub sha256_wheel: Option<String>,
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
pub struct OracleProvenance {
pub oracle: OracleProvenanceInner,
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
pub struct OracleProvenanceInner {
pub package: String,
pub version: String,
pub source: String,
pub license: String,
pub retrieval_date: String,
}
#[derive(Debug, Clone, Error, PartialEq, Eq)]
pub enum OracleError {
#[error("file I/O error: {message}")]
Io { message: String },
#[error("TOML parse error: {message}")]
TomlParse { message: String },
#[error("expected pproxy version \"{expected}\" but found \"{found}\"")]
VersionMismatch { expected: String, found: String },
#[error("expected pproxy package \"{expected}\" but found \"{found}\"")]
PackageMismatch { expected: String, found: String },
#[error("wheel hash mismatch: expected \"{expected}\" but computed \"{found}\"")]
WheelHashMismatch { expected: String, found: String },
#[error("no wheel hash recorded in hashes.toml")]
MissingWheelHash,
#[error("hash computation failed: {message}")]
HashComputationFailed { message: String },
}
pub fn load_oracle_hashes(manifest_dir: &Path) -> Result<OracleHashes, OracleError> {
let path = manifest_dir.join("compat/pproxy-2.7.9/hashes.toml");
let content = fs::read_to_string(&path).map_err(|e| OracleError::Io {
message: format!("failed to read {}: {}", path.display(), e),
})?;
let hashes: OracleHashes = toml::from_str(&content).map_err(|e| OracleError::TomlParse {
message: e.to_string(),
})?;
Ok(hashes)
}
pub fn load_oracle_provenance(manifest_dir: &Path) -> Result<OracleProvenance, OracleError> {
let path = manifest_dir.join("compat/pproxy-2.7.9/provenance.toml");
let content = fs::read_to_string(&path).map_err(|e| OracleError::Io {
message: format!("failed to read {}: {}", path.display(), e),
})?;
let prov: OracleProvenance = toml::from_str(&content).map_err(|e| OracleError::TomlParse {
message: e.to_string(),
})?;
Ok(prov)
}
pub fn verify_manifest_oracle_version(
manifest: &StrictManifest,
provenance: &OracleProvenance,
) -> Result<(), OracleError> {
if manifest.meta.pproxy_version != provenance.oracle.version {
return Err(OracleError::VersionMismatch {
expected: provenance.oracle.version.clone(),
found: manifest.meta.pproxy_version.clone(),
});
}
if provenance.oracle.package != "pproxy" {
return Err(OracleError::PackageMismatch {
expected: "pproxy".to_string(),
found: provenance.oracle.package.clone(),
});
}
Ok(())
}
pub fn verify_wheel_hash(_wheel_path: &Path, _expected_hash: &str) -> Result<(), OracleError> {
Err(OracleError::HashComputationFailed {
message: "sha2 feature required for hash verification; use oracle runner at runtime"
.to_string(),
})
}
pub fn validate_strict_manifest(manifest: &StrictManifest) -> Result<(), StrictValidationErrors> {
let mut errs = StrictValidationErrors::new();
let mut seen_ids = HashSet::new();
for rec in &manifest.record {
if !seen_ids.insert(rec.id.clone()) {
errs.push(StrictValidationError::DuplicateId { id: rec.id.clone() });
}
}
for rec in &manifest.record {
if rec.id.is_empty() {
errs.push(StrictValidationError::EmptyId);
continue;
}
if !rec.category.is_empty() && !ALLOWED_CATEGORIES.contains(&rec.category.as_str()) {
errs.push(StrictValidationError::UnknownCategory {
value: rec.category.clone(),
allowed: ALLOWED_CATEGORIES.iter().map(|s| s.to_string()).collect(),
});
}
if !rec.status.is_empty() && !ALLOWED_STATUSES.contains(&rec.status.as_str()) {
errs.push(StrictValidationError::UnknownStatus {
value: rec.status.clone(),
allowed: ALLOWED_STATUSES.iter().map(|s| s.to_string()).collect(),
});
}
if !rec.comparator.is_empty() && !ALLOWED_COMPARATORS.contains(&rec.comparator.as_str()) {
errs.push(StrictValidationError::UnknownComparator {
value: rec.comparator.clone(),
allowed: ALLOWED_COMPARATORS.iter().map(|s| s.to_string()).collect(),
});
}
if !rec.owner.is_empty() && !ALLOWED_OWNERS.contains(&rec.owner.as_str()) {
errs.push(StrictValidationError::UnknownOwner {
value: rec.owner.clone(),
allowed: ALLOWED_OWNERS.iter().map(|s| s.to_string()).collect(),
});
}
if !rec.milestone.is_empty() && !ALLOWED_MILESTONES.contains(&rec.milestone.as_str()) {
errs.push(StrictValidationError::UnknownMilestone {
value: rec.milestone.clone(),
allowed: ALLOWED_MILESTONES.iter().map(|s| s.to_string()).collect(),
});
}
if !rec.evidence_level.is_empty()
&& !ALLOWED_EVIDENCE_LEVELS.contains(&rec.evidence_level.as_str())
{
errs.push(StrictValidationError::UnknownEvidenceLevel {
value: rec.evidence_level.clone(),
allowed: ALLOWED_EVIDENCE_LEVELS
.iter()
.map(|s| s.to_string())
.collect(),
});
}
if !rec.implementation_state.is_empty()
&& !ALLOWED_IMPLEMENTATION_STATES.contains(&rec.implementation_state.as_str())
{
errs.push(StrictValidationError::UnknownImplementationState {
value: rec.implementation_state.clone(),
allowed: ALLOWED_IMPLEMENTATION_STATES
.iter()
.map(|s| s.to_string())
.collect(),
});
}
if rec.status == "drop_in" && rec.evidence_refs.is_empty() && rec.test_refs.is_empty() {
errs.push(StrictValidationError::DropInWithoutEvidence { id: rec.id.clone() });
}
if rec.status == "drop_in" && rec.oracle_probe.is_empty() {
errs.push(StrictValidationError::DropInWithoutOracleProbe { id: rec.id.clone() });
}
if let Some(rec_idx) = milestone_index(&rec.milestone) {
if let Some(cur_idx) = milestone_index(CURRENT_MILESTONE) {
if rec_idx <= cur_idx && !TERMINAL_STATUSES.contains(&rec.status.as_str()) {
errs.push(StrictValidationError::UnresolvedProgress {
id: rec.id.clone(),
status: rec.status.clone(),
milestone: rec.milestone.clone(),
current: CURRENT_MILESTONE.to_string(),
});
}
}
}
if rec.status == "drop_in"
&& !rec.evidence_level.is_empty()
&& rec.evidence_level != "paired_oracle"
&& rec.evidence_level != "bidirectional_interop"
{
errs.push(StrictValidationError::DropInRequiresStrongEvidence {
id: rec.id.clone(),
evidence_level: rec.evidence_level.clone(),
});
}
let is_structural_comparator = matches!(
rec.comparator.as_str(),
"module_existence"
| "constant_value"
| "enum_membership"
| "method_signature"
| "property_existence"
| "class_hierarchy"
);
if rec.status == "drop_in"
&& is_structural_comparator
&& (rec.evidence_level == "structural_only" || rec.evidence_level == "none")
{
errs.push(
StrictValidationError::StructuralComparatorDropInRequiresEvidence {
id: rec.id.clone(),
comparator: rec.comparator.clone(),
evidence_level: rec.evidence_level.clone(),
},
);
}
if rec.evidence_level == "structural_only" && rec.status == "drop_in" {
errs.push(
StrictValidationError::StructuralOnlyIncompatibleWithDropIn { id: rec.id.clone() },
);
}
if !rec.certification_scope.is_empty()
&& !ALLOWED_CERTIFICATION_SCOPES.contains(&rec.certification_scope.as_str())
{
errs.push(StrictValidationError::UnknownCertificationScope {
value: rec.certification_scope.clone(),
allowed: ALLOWED_CERTIFICATION_SCOPES
.iter()
.map(|s| s.to_string())
.collect(),
});
}
if rec.status == "drop_in"
&& rec.certification_scope == "behavioral"
&& is_structural_comparator
{
errs.push(
StrictValidationError::StructuralComparatorBehavioralScopeMismatch {
id: rec.id.clone(),
comparator: rec.comparator.clone(),
},
);
}
if rec.closure_required && rec.evidence_refs.is_empty() {
errs.push(StrictValidationError::ClosureRequiredWithoutEvidence { id: rec.id.clone() });
}
if rec.closure_required
&& rec.certification_scope == "structural"
&& rec.behavior_record.is_none()
&& !rec.inventory_only
{
errs.push(StrictValidationError::StructuralMissingBehaviorRecord {
id: rec.id.clone(),
});
}
}
if errs.is_empty() {
Ok(())
} else {
Err(errs)
}
}
pub fn validate_strict_manifest_file(
path: &Path,
) -> Result<StrictManifest, StrictValidationErrors> {
let content = fs::read_to_string(path).map_err(|e| {
let mut errs = StrictValidationErrors::new();
errs.push(StrictValidationError::Io {
message: format!("failed to read {}: {}", path.display(), e),
});
errs
})?;
let manifest: StrictManifest = toml::from_str(&content).map_err(|e| {
let mut errs = StrictValidationErrors::new();
errs.push(StrictValidationError::TomlParse {
message: e.to_string(),
});
errs
})?;
validate_strict_manifest(&manifest)?;
Ok(manifest)
}
#[derive(Debug, Clone)]
pub struct StrictManifestSummary {
pub total: usize,
pub by_status: Vec<(String, usize)>,
pub by_category: Vec<(String, usize)>,
pub by_owner: Vec<(String, usize)>,
pub by_milestone: Vec<(String, usize)>,
pub by_certification_scope: Vec<(String, usize)>,
pub terminal_count: usize,
pub gap_count: usize,
}
pub fn summarize_manifest(manifest: &StrictManifest) -> StrictManifestSummary {
use std::collections::HashMap;
let mut status_counts: HashMap<String, usize> = HashMap::new();
let mut category_counts: HashMap<String, usize> = HashMap::new();
let mut owner_counts: HashMap<String, usize> = HashMap::new();
let mut milestone_counts: HashMap<String, usize> = HashMap::new();
let mut scope_counts: HashMap<String, usize> = HashMap::new();
let mut terminal = 0;
let mut gaps = 0;
for rec in &manifest.record {
*status_counts.entry(rec.status.clone()).or_insert(0) += 1;
*category_counts.entry(rec.category.clone()).or_insert(0) += 1;
if !rec.owner.is_empty() {
*owner_counts.entry(rec.owner.clone()).or_insert(0) += 1;
}
if !rec.milestone.is_empty() {
*milestone_counts.entry(rec.milestone.clone()).or_insert(0) += 1;
}
*scope_counts
.entry(rec.certification_scope.clone())
.or_insert(0) += 1;
if TERMINAL_STATUSES.contains(&rec.status.as_str()) {
terminal += 1;
} else {
gaps += 1;
}
}
let mut by_status: Vec<_> = status_counts.into_iter().collect();
by_status.sort_by_key(|(_, count)| std::cmp::Reverse(*count));
let mut by_category: Vec<_> = category_counts.into_iter().collect();
by_category.sort_by_key(|(_, count)| std::cmp::Reverse(*count));
let mut by_owner: Vec<_> = owner_counts.into_iter().collect();
by_owner.sort_by_key(|(_, count)| std::cmp::Reverse(*count));
let mut by_milestone: Vec<_> = milestone_counts.into_iter().collect();
by_milestone.sort_by_key(|(_, count)| std::cmp::Reverse(*count));
let mut by_certification_scope: Vec<_> = scope_counts.into_iter().collect();
by_certification_scope.sort_by_key(|(_, count)| std::cmp::Reverse(*count));
StrictManifestSummary {
total: manifest.record.len(),
by_status,
by_category,
by_owner,
by_milestone,
by_certification_scope,
terminal_count: terminal,
gap_count: gaps,
}
}
pub fn generate_strict_report(manifest: &StrictManifest) -> String {
let summary = summarize_manifest(manifest);
let mut out = String::with_capacity(4096);
out.push_str("# pproxy 2.7.9 Strict Compatibility Report\n\n");
out.push_str(&format!(
"**Oracle version:** pproxy=={}\n",
manifest.meta.pproxy_version
));
out.push_str(&format!("**Manifest schema:** {}\n", manifest.meta.schema));
out.push_str(&format!("**Policy:** {}\n", manifest.meta.policy_ref));
out.push_str(&format!("**Oracle ref:** {}\n\n", manifest.meta.oracle_ref));
out.push_str("## Summary\n\n");
out.push_str("| Metric | Count |\n");
out.push_str("|--------|-------|\n");
out.push_str(&format!("| Total records | {} |\n", summary.total));
out.push_str(&format!(
"| Terminal (resolved) | {} |\n",
summary.terminal_count
));
out.push_str(&format!("| Gap (unresolved) | {} |\n", summary.gap_count));
out.push_str(&format!(
"| Certification readiness | {:.0}% |\n\n",
if summary.total > 0 {
(summary.terminal_count as f64 / summary.total as f64) * 100.0
} else {
0.0
}
));
out.push_str("### By Status\n\n");
out.push_str("| Status | Count |\n");
out.push_str("|--------|-------|\n");
for (status, count) in &summary.by_status {
out.push_str(&format!("| {} | {} |\n", status, count));
}
out.push('\n');
out.push_str("### By Category\n\n");
out.push_str("| Category | Count |\n");
out.push_str("|----------|-------|\n");
for (category, count) in &summary.by_category {
out.push_str(&format!("| {} | {} |\n", category, count));
}
out.push('\n');
out.push_str("### By Owner\n\n");
out.push_str("| Owner | Count |\n");
out.push_str("|-------|-------|\n");
for (owner, count) in &summary.by_owner {
out.push_str(&format!("| {} | {} |\n", owner, count));
}
out.push('\n');
out.push_str("### By Milestone\n\n");
out.push_str("| Milestone | Count |\n");
out.push_str("|-----------|-------|\n");
for (milestone, count) in &summary.by_milestone {
out.push_str(&format!("| {} | {} |\n", milestone, count));
}
out.push('\n');
out.push_str("### By Certification Scope\n\n");
out.push_str("| Scope | Count |\n");
out.push_str("|-------|-------|\n");
for (scope, count) in &summary.by_certification_scope {
out.push_str(&format!("| {} | {} |\n", scope, count));
}
out.push('\n');
out.push_str("## Gap Records\n\n");
out.push_str("Records with non-terminal status requiring resolution:\n\n");
let gaps: Vec<_> = manifest
.record
.iter()
.filter(|r| !TERMINAL_STATUSES.contains(&r.status.as_str()))
.collect();
if gaps.is_empty() {
out.push_str("_No unresolved gaps._\n\n");
} else {
out.push_str("| ID | Status | Category | Owner | Milestone |\n");
out.push_str("|----|--------|----------|-------|----------|\n");
for rec in &gaps {
out.push_str(&format!(
"| {} | {} | {} | {} | {} |\n",
rec.id, rec.status, rec.category, rec.owner, rec.milestone
));
}
out.push('\n');
}
out.push_str("## Terminal Records\n\n");
let terminals: Vec<_> = manifest
.record
.iter()
.filter(|r| TERMINAL_STATUSES.contains(&r.status.as_str()))
.collect();
if terminals.is_empty() {
out.push_str("_No terminal records._\n\n");
} else {
out.push_str("| ID | Status | Category | Notes |\n");
out.push_str("|----|--------|----------|-------|\n");
for rec in &terminals {
let notes = if rec.notes.is_empty() {
"-".to_string()
} else if rec.notes.len() > 80 {
format!("{}...", &rec.notes[..77])
} else {
rec.notes.clone()
};
out.push_str(&format!(
"| {} | {} | {} | {} |\n",
rec.id, rec.status, rec.category, notes
));
}
out.push('\n');
}
out.push_str("## Structural Inventory Records\n\n");
let structural: Vec<_> = manifest
.record
.iter()
.filter(|r| r.certification_scope == "structural")
.collect();
if structural.is_empty() {
out.push_str("_No structural inventory records._\n\n");
} else {
out.push_str("| ID | Status | Comparator | Evidence Level | Behavior Record |\n");
out.push_str("|----|--------|------------|----------------|------------------|\n");
for rec in &structural {
let behavior = rec.behavior_record.as_deref().unwrap_or("-");
out.push_str(&format!(
"| {} | {} | {} | {} | {} |\n",
rec.id, rec.status, rec.comparator, rec.evidence_level, behavior
));
}
out.push('\n');
}
out.push_str("## Behaviorally Certified Records\n\n");
let behavioral: Vec<_> = manifest
.record
.iter()
.filter(|r| r.certification_scope == "behavioral")
.collect();
if behavioral.is_empty() {
out.push_str("_No behaviorally certified records._\n\n");
} else {
out.push_str("| ID | Status | Comparator | Evidence Level |\n");
out.push_str("|----|--------|------------|----------------|\n");
for rec in &behavioral {
out.push_str(&format!(
"| {} | {} | {} | {} |\n",
rec.id, rec.status, rec.comparator, rec.evidence_level
));
}
out.push('\n');
}
out.push_str("## Intentional Non-Parity Records\n\n");
let non_parity: Vec<_> = manifest
.record
.iter()
.filter(|r| r.status == "intentional_non_parity")
.collect();
if non_parity.is_empty() {
out.push_str("_No intentional non-parity records._\n\n");
} else {
out.push_str("| ID | Category | Notes |\n");
out.push_str("|----|----------|-------|\n");
for rec in &non_parity {
let notes = if rec.notes.is_empty() {
"-".to_string()
} else if rec.notes.len() > 80 {
format!("{}...", &rec.notes[..77])
} else {
rec.notes.clone()
};
out.push_str(&format!("| {} | {} | {} |\n", rec.id, rec.category, notes));
}
out.push('\n');
}
out.push_str("## Platform-Constrained Records\n\n");
let platform: Vec<_> = manifest
.record
.iter()
.filter(|r| r.status == "platform_constraint" || r.certification_scope == "platform")
.collect();
if platform.is_empty() {
out.push_str("_No platform-constrained records._\n\n");
} else {
out.push_str("| ID | Status | Platforms | Notes |\n");
out.push_str("|----|--------|-----------|-------|\n");
for rec in &platform {
let platforms = if rec.platforms.is_empty() {
"-".to_string()
} else {
rec.platforms.join(", ")
};
let notes = if rec.notes.is_empty() {
"-".to_string()
} else if rec.notes.len() > 60 {
format!("{}...", &rec.notes[..57])
} else {
rec.notes.clone()
};
out.push_str(&format!(
"| {} | {} | {} | {} |\n",
rec.id, rec.status, platforms, notes
));
}
out.push('\n');
}
out.push_str("## Unresolved Behavior Gaps\n\n");
let behavior_gaps: Vec<_> = manifest
.record
.iter()
.filter(|r| {
!TERMINAL_STATUSES.contains(&r.status.as_str()) && r.certification_scope == "behavioral"
})
.collect();
if behavior_gaps.is_empty() {
out.push_str("_No unresolved behavior gaps._\n\n");
} else {
out.push_str("| ID | Status | Category | Owner | Milestone |\n");
out.push_str("|----|--------|----------|-------|----------|\n");
for rec in &behavior_gaps {
out.push_str(&format!(
"| {} | {} | {} | {} | {} |\n",
rec.id, rec.status, rec.category, rec.owner, rec.milestone
));
}
out.push('\n');
}
out.push_str("## Missing or Stale Evidence\n\n");
let missing_evidence: Vec<_> = manifest
.record
.iter()
.filter(|r| r.closure_required && r.evidence_refs.is_empty())
.collect();
if missing_evidence.is_empty() {
out.push_str("_No records with missing required evidence._\n\n");
} else {
out.push_str("| ID | Status | Certification Scope | Closure Required |\n");
out.push_str("|----|--------|---------------------|------------------|\n");
for rec in &missing_evidence {
out.push_str(&format!(
"| {} | {} | {} | {} |\n",
rec.id, rec.status, rec.certification_scope, rec.closure_required
));
}
out.push('\n');
}
out
}
pub fn write_strict_report(
manifest: &StrictManifest,
output_path: &Path,
) -> Result<(), std::io::Error> {
let report = generate_strict_report(manifest);
if let Some(parent) = output_path.parent() {
fs::create_dir_all(parent)?;
}
fs::write(output_path, report)
}
#[cfg(test)]
#[allow(clippy::all)]
mod tests {
use super::*;
fn make_meta() -> StrictManifestMeta {
StrictManifestMeta {
manifest_version: "1".to_string(),
pproxy_version: "2.7.9".to_string(),
schema: "strict_1".to_string(),
policy_ref: String::new(),
oracle_ref: String::new(),
closure_through: "C".to_string(),
}
}
fn make_manifest(records: Vec<StrictRecord>) -> StrictManifest {
StrictManifest {
meta: make_meta(),
record: records,
}
}
fn default_record(id: &str) -> StrictRecord {
StrictRecord {
id: id.to_string(),
category: "protocol".to_string(),
kind: "role".to_string(),
module: "http".to_string(),
name: format!("Test {id}"),
oracle_probe: "test.probe".to_string(),
candidate_probe: "test.probe".to_string(),
comparator: "protocol_wire".to_string(),
status: "drop_in".to_string(),
owner: "track-b".to_string(),
milestone: "B".to_string(),
platforms: vec!["linux".to_string()],
python_versions: vec![],
depends_on: vec![],
test_refs: vec!["test_ref".to_string()],
evidence_refs: vec!["evidence_ref".to_string()],
notes: String::new(),
evidence_level: "paired_oracle".to_string(),
implementation_state: "functional".to_string(),
certification_scope: "behavioral".to_string(),
closure_required: true,
behavior_record: None,
inventory_only: false,
}
}
#[test]
fn valid_manifest_passes() {
let rec = default_record("test.ok");
let manifest = make_manifest(vec![rec]);
let result = validate_strict_manifest(&manifest);
assert!(result.is_ok(), "expected Ok, got {:?}", result.err());
}
#[test]
fn duplicate_ids_fail() {
let manifest = make_manifest(vec![default_record("dup"), default_record("dup")]);
let errs = validate_strict_manifest(&manifest).unwrap_err();
assert!(
errs.errors
.iter()
.any(|e| matches!(e, StrictValidationError::DuplicateId { id, .. } if id == "dup")),
"expected DuplicateId"
);
}
#[test]
fn empty_id_fails() {
let rec = StrictRecord {
id: String::new(),
..default_record("unused")
};
let manifest = make_manifest(vec![rec]);
let errs = validate_strict_manifest(&manifest).unwrap_err();
assert!(
errs.errors
.iter()
.any(|e| matches!(e, StrictValidationError::EmptyId)),
"expected EmptyId"
);
}
#[test]
fn unknown_category_fails() {
let mut rec = default_record("bad_cat");
rec.category = "bogus".to_string();
let manifest = make_manifest(vec![rec]);
let errs = validate_strict_manifest(&manifest).unwrap_err();
assert!(
errs.errors.iter().any(|e| matches!(
e,
StrictValidationError::UnknownCategory { value, .. } if value == "bogus"
)),
"expected UnknownCategory"
);
}
#[test]
fn unknown_status_fails() {
let mut rec = default_record("bad_status");
rec.status = "bogus".to_string();
let manifest = make_manifest(vec![rec]);
let errs = validate_strict_manifest(&manifest).unwrap_err();
assert!(
errs.errors.iter().any(|e| matches!(
e,
StrictValidationError::UnknownStatus { value, .. } if value == "bogus"
)),
"expected UnknownStatus"
);
}
#[test]
fn unknown_comparator_fails() {
let mut rec = default_record("bad_comp");
rec.comparator = "bogus".to_string();
let manifest = make_manifest(vec![rec]);
let errs = validate_strict_manifest(&manifest).unwrap_err();
assert!(
errs.errors.iter().any(|e| matches!(
e,
StrictValidationError::UnknownComparator { value, .. } if value == "bogus"
)),
"expected UnknownComparator"
);
}
#[test]
fn unknown_owner_fails() {
let mut rec = default_record("bad_owner");
rec.owner = "bogus".to_string();
let manifest = make_manifest(vec![rec]);
let errs = validate_strict_manifest(&manifest).unwrap_err();
assert!(
errs.errors.iter().any(|e| matches!(
e,
StrictValidationError::UnknownOwner { value, .. } if value == "bogus"
)),
"expected UnknownOwner"
);
}
#[test]
fn unknown_milestone_fails() {
let mut rec = default_record("bad_ms");
rec.milestone = "Z".to_string();
let manifest = make_manifest(vec![rec]);
let errs = validate_strict_manifest(&manifest).unwrap_err();
assert!(
errs.errors.iter().any(|e| matches!(
e,
StrictValidationError::UnknownMilestone { value, .. } if value == "Z"
)),
"expected UnknownMilestone"
);
}
#[test]
fn drop_in_without_evidence_fails() {
let mut rec = default_record("no_ev");
rec.status = "drop_in".to_string();
rec.evidence_refs = vec![];
rec.test_refs = vec![];
let manifest = make_manifest(vec![rec]);
let errs = validate_strict_manifest(&manifest).unwrap_err();
assert!(
errs.errors.iter().any(|e| matches!(
e,
StrictValidationError::DropInWithoutEvidence { id, .. } if id == "no_ev"
)),
"expected DropInWithoutEvidence"
);
}
#[test]
fn drop_in_without_oracle_probe_fails() {
let mut rec = default_record("no_probe");
rec.status = "drop_in".to_string();
rec.oracle_probe = String::new();
let manifest = make_manifest(vec![rec]);
let errs = validate_strict_manifest(&manifest).unwrap_err();
assert!(
errs.errors.iter().any(|e| matches!(
e,
StrictValidationError::DropInWithoutOracleProbe { id, .. } if id == "no_probe"
)),
"expected DropInWithoutOracleProbe"
);
}
#[test]
fn drop_in_with_evidence_passes() {
let mut rec = default_record("with_ev");
rec.status = "drop_in".to_string();
rec.evidence_refs = vec!["some_evidence".to_string()];
let manifest = make_manifest(vec![rec]);
let result = validate_strict_manifest(&manifest);
assert!(result.is_ok(), "expected Ok, got {:?}", result.err());
}
#[test]
fn drop_in_with_tests_passes() {
let mut rec = default_record("with_tests");
rec.status = "drop_in".to_string();
rec.test_refs = vec!["some_test".to_string()];
rec.evidence_refs = vec![];
rec.closure_required = false; let manifest = make_manifest(vec![rec]);
let result = validate_strict_manifest(&manifest);
assert!(result.is_ok(), "expected Ok, got {:?}", result.err());
}
#[test]
fn gap_at_current_milestone_fails() {
let mut rec = default_record("gap_ms");
rec.status = "gap".to_string();
rec.milestone = "A".to_string(); let manifest = make_manifest(vec![rec]);
let errs = validate_strict_manifest(&manifest).unwrap_err();
assert!(
errs.errors.iter().any(|e| matches!(
e,
StrictValidationError::UnresolvedProgress { id, status, .. }
if id == "gap_ms" && status == "gap"
)),
"expected UnresolvedProgress for gap at milestone A"
);
}
#[test]
fn drop_in_at_current_milestone_passes() {
let mut rec = default_record("di_ms");
rec.status = "drop_in".to_string();
rec.milestone = "A".to_string();
let manifest = make_manifest(vec![rec]);
let result = validate_strict_manifest(&manifest);
assert!(result.is_ok(), "expected Ok, got {:?}", result.err());
}
#[test]
fn gap_at_future_milestone_passes() {
let mut rec = default_record("gap_future");
rec.status = "gap".to_string();
rec.milestone = "E".to_string(); let manifest = make_manifest(vec![rec]);
let result = validate_strict_manifest(&manifest);
assert!(result.is_ok(), "expected Ok, got {:?}", result.err());
}
#[test]
fn multiple_errors_collected() {
let mut rec = default_record("dup");
rec.category = "bogus".to_string();
let manifest = make_manifest(vec![rec, default_record("dup")]);
let errs = validate_strict_manifest(&manifest).unwrap_err();
assert!(
errs.len() >= 2,
"expected at least 2 errors, got {}",
errs.len()
);
assert!(errs
.errors
.iter()
.any(|e| matches!(e, StrictValidationError::DuplicateId { .. })));
assert!(errs
.errors
.iter()
.any(|e| matches!(e, StrictValidationError::UnknownCategory { .. })));
}
#[test]
fn all_allowed_categories_are_valid() {
for cat in ALLOWED_CATEGORIES {
let mut rec = default_record(&format!("cat_{cat}"));
rec.category = cat.to_string();
rec.status = "gap".to_string();
rec.milestone = "F".to_string(); let manifest = make_manifest(vec![rec]);
let errs = validate_strict_manifest(&manifest);
if let Err(ref e) = errs {
assert!(
!e.errors
.iter()
.any(|e| matches!(e, StrictValidationError::UnknownCategory { .. })),
"category \"{cat}\" should be valid"
);
}
}
}
#[test]
fn all_allowed_statuses_are_valid() {
for status in ALLOWED_STATUSES {
let mut rec = default_record(&format!("status_{status}"));
rec.status = status.to_string();
rec.milestone = "F".to_string();
let manifest = make_manifest(vec![rec]);
let errs = validate_strict_manifest(&manifest);
if let Err(ref e) = errs {
assert!(
!e.errors
.iter()
.any(|e| matches!(e, StrictValidationError::UnknownStatus { .. })),
"status \"{status}\" should be valid"
);
}
}
}
#[test]
fn all_allowed_comparators_are_valid() {
for comp in ALLOWED_COMPARATORS {
let mut rec = default_record(&format!("comp_{comp}"));
rec.comparator = comp.to_string();
rec.status = "gap".to_string();
rec.milestone = "F".to_string();
let manifest = make_manifest(vec![rec]);
let errs = validate_strict_manifest(&manifest);
if let Err(ref e) = errs {
assert!(
!e.errors
.iter()
.any(|e| matches!(e, StrictValidationError::UnknownComparator { .. })),
"comparator \"{comp}\" should be valid"
);
}
}
}
#[test]
fn all_allowed_owners_are_valid() {
for owner in ALLOWED_OWNERS {
let mut rec = default_record(&format!("owner_{owner}"));
rec.owner = owner.to_string();
rec.status = "gap".to_string();
rec.milestone = "F".to_string();
let manifest = make_manifest(vec![rec]);
let errs = validate_strict_manifest(&manifest);
if let Err(ref e) = errs {
assert!(
!e.errors
.iter()
.any(|e| matches!(e, StrictValidationError::UnknownOwner { .. })),
"owner \"{owner}\" should be valid"
);
}
}
}
#[test]
fn all_allowed_milestones_are_valid() {
for ms in ALLOWED_MILESTONES {
let mut rec = default_record(&format!("ms_{ms}"));
rec.milestone = ms.to_string();
rec.status = "gap".to_string();
let manifest = make_manifest(vec![rec]);
let errs = validate_strict_manifest(&manifest);
if let Err(ref e) = errs {
assert!(
!e.errors
.iter()
.any(|e| matches!(e, StrictValidationError::UnknownMilestone { .. })),
"milestone \"{ms}\" should be valid"
);
}
}
}
#[test]
fn validation_errors_collection() {
let mut errs = StrictValidationErrors::new();
assert!(errs.is_empty());
assert_eq!(errs.len(), 0);
errs.push(StrictValidationError::EmptyId);
errs.push(StrictValidationError::DuplicateId {
id: "a".to_string(),
});
assert!(!errs.is_empty());
assert_eq!(errs.len(), 2);
}
#[test]
fn validate_strict_manifest_file_missing_path() {
let path = Path::new("/nonexistent/path/strict_manifest.toml");
let result = validate_strict_manifest_file(path);
assert!(result.is_err());
let errs = result.unwrap_err();
assert!(errs
.errors
.iter()
.any(|e| matches!(e, StrictValidationError::Io { .. })));
}
#[test]
fn toml_parse_error() {
let bad_toml = "this is not [valid toml {{{{";
let result: Result<StrictManifest, _> = toml::from_str(bad_toml);
assert!(result.is_err());
}
#[test]
fn validate_real_strict_manifest() {
let path = match find_strict_manifest_path() {
Some(p) => p,
None => {
eprintln!("strict manifest not found, skipping");
return;
}
};
eprintln!("Validating strict manifest at: {}", path.display());
match validate_strict_manifest_file(&path) {
Ok(manifest) => {
eprintln!(
"Strict manifest OK: {} records, meta.schema={}",
manifest.record.len(),
manifest.meta.schema
);
}
Err(errs) => {
eprintln!(
"Strict manifest validation FAILED with {} errors:",
errs.len()
);
for (i, err) in errs.errors.iter().enumerate() {
eprintln!(" ERROR {}: {}", i + 1, err);
}
panic!(
"strict manifest validation failed with {} errors (see above)",
errs.len()
);
}
}
}
#[test]
fn milestone_index_ordering() {
assert!(milestone_index("A") < milestone_index("B"));
assert!(milestone_index("B") < milestone_index("C"));
assert!(milestone_index("C") < milestone_index("D"));
assert!(milestone_index("D") < milestone_index("E"));
assert!(milestone_index("E") < milestone_index("F"));
}
#[test]
fn terminal_statuses_not_flagged_at_current_milestone() {
for status in TERMINAL_STATUSES {
let mut rec = default_record(&format!("term_{status}"));
rec.status = status.to_string();
rec.milestone = "B".to_string();
let manifest = make_manifest(vec![rec]);
let errs = validate_strict_manifest(&manifest);
if let Err(ref e) = errs {
assert!(
!e.errors
.iter()
.any(|e| matches!(e, StrictValidationError::UnresolvedProgress { .. })),
"terminal status \"{status}\" should not be flagged at current milestone"
);
}
}
}
#[test]
fn gap_at_milestone_a_also_flagged() {
let mut rec = default_record("gap_a");
rec.status = "gap".to_string();
rec.milestone = "A".to_string();
let manifest = make_manifest(vec![rec]);
let errs = validate_strict_manifest(&manifest).unwrap_err();
assert!(
errs.errors
.iter()
.any(|e| matches!(e, StrictValidationError::UnresolvedProgress { .. })),
"gap at milestone A should be flagged"
);
}
#[test]
fn verify_manifest_oracle_version_matches() {
let manifest = make_manifest(vec![]);
let provenance = OracleProvenance {
oracle: OracleProvenanceInner {
package: "pproxy".to_string(),
version: "2.7.9".to_string(),
source: "pypi".to_string(),
license: "MIT".to_string(),
retrieval_date: "2026-07-16".to_string(),
},
};
assert!(verify_manifest_oracle_version(&manifest, &provenance).is_ok());
}
#[test]
fn verify_manifest_oracle_version_mismatch() {
let mut meta = make_meta();
meta.pproxy_version = "2.7.8".to_string();
let manifest = StrictManifest {
meta,
record: vec![],
};
let provenance = OracleProvenance {
oracle: OracleProvenanceInner {
package: "pproxy".to_string(),
version: "2.7.9".to_string(),
source: "pypi".to_string(),
license: "MIT".to_string(),
retrieval_date: "2026-07-16".to_string(),
},
};
let err = verify_manifest_oracle_version(&manifest, &provenance).unwrap_err();
assert!(matches!(err, OracleError::VersionMismatch { .. }));
}
#[test]
fn verify_manifest_oracle_package_mismatch() {
let manifest = make_manifest(vec![]);
let provenance = OracleProvenance {
oracle: OracleProvenanceInner {
package: "not_pproxy".to_string(),
version: "2.7.9".to_string(),
source: "pypi".to_string(),
license: "MIT".to_string(),
retrieval_date: "2026-07-16".to_string(),
},
};
let err = verify_manifest_oracle_version(&manifest, &provenance).unwrap_err();
assert!(matches!(err, OracleError::PackageMismatch { .. }));
}
#[test]
fn load_oracle_hashes_from_workspace() {
if let Ok(manifest_dir) = std::env::var("CARGO_MANIFEST_DIR") {
let path = PathBuf::from(&manifest_dir);
match load_oracle_hashes(&path) {
Ok(hashes) => {
assert_eq!(hashes.package.version, "2.7.9");
assert!(hashes.package.sha256_wheel.is_some());
let wheel_hash = hashes.package.sha256_wheel.unwrap();
assert_ne!(wheel_hash, "placeholder_update_on_first_run");
assert_eq!(wheel_hash.len(), 64); }
Err(e) => {
eprintln!("load_oracle_hashes: {}", e);
}
}
}
}
#[test]
fn load_oracle_provenance_from_workspace() {
if let Ok(manifest_dir) = std::env::var("CARGO_MANIFEST_DIR") {
let path = PathBuf::from(&manifest_dir);
match load_oracle_provenance(&path) {
Ok(prov) => {
assert_eq!(prov.oracle.package, "pproxy");
assert_eq!(prov.oracle.version, "2.7.9");
assert_eq!(prov.oracle.source, "pypi");
}
Err(e) => {
eprintln!("load_oracle_provenance: {}", e);
}
}
}
}
#[test]
fn manifest_version_matches_provenance() {
if let Ok(manifest_dir) = std::env::var("CARGO_MANIFEST_DIR") {
let path = PathBuf::from(&manifest_dir);
let hashes = load_oracle_hashes(&path);
let provenance = load_oracle_provenance(&path);
if let (Ok(h), Ok(p)) = (hashes, provenance) {
assert_eq!(h.package.version, p.oracle.version);
}
}
}
#[test]
fn summarize_manifest_basic() {
let mut r1 = default_record("a");
r1.status = "drop_in".to_string();
r1.category = "protocol".to_string();
r1.owner = "track-b".to_string();
let mut r2 = default_record("b");
r2.status = "gap".to_string();
r2.category = "python_namespace".to_string();
r2.owner = "track-a".to_string();
r2.milestone = "F".to_string(); let manifest = make_manifest(vec![r1, r2]);
let summary = summarize_manifest(&manifest);
assert_eq!(summary.total, 2);
assert_eq!(summary.terminal_count, 1);
assert_eq!(summary.gap_count, 1);
assert!(!summary.by_certification_scope.is_empty());
}
#[test]
fn summarize_manifest_all_terminal() {
let mut r1 = default_record("a");
r1.status = "drop_in".to_string();
let mut r2 = default_record("b");
r2.status = "not_applicable".to_string();
let manifest = make_manifest(vec![r1, r2]);
let summary = summarize_manifest(&manifest);
assert_eq!(summary.total, 2);
assert_eq!(summary.terminal_count, 2);
assert_eq!(summary.gap_count, 0);
}
#[test]
fn generate_strict_report_basic() {
let mut r1 = default_record("a");
r1.status = "drop_in".to_string();
r1.category = "protocol".to_string();
r1.notes = "Test note".to_string();
let mut r2 = default_record("b");
r2.status = "gap".to_string();
r2.category = "python_namespace".to_string();
let manifest = make_manifest(vec![r1, r2]);
let report = generate_strict_report(&manifest);
assert!(report.contains("# pproxy 2.7.9 Strict Compatibility Report"));
assert!(report.contains("pproxy==2.7.9"));
assert!(report.contains("Total records"));
assert!(report.contains("Gap Records"));
assert!(report.contains("Terminal Records"));
}
#[test]
fn generate_strict_report_empty() {
let manifest = make_manifest(vec![]);
let report = generate_strict_report(&manifest);
assert!(report.contains("Total records"));
assert!(report.contains("_No unresolved gaps._"));
assert!(report.contains("_No terminal records._"));
}
#[test]
fn write_strict_report_to_temp() {
let manifest = make_manifest(vec![]);
let dir = std::env::temp_dir().join("eggress_strict_report_test");
let path = dir.join("report.md");
let result = write_strict_report(&manifest, &path);
assert!(result.is_ok());
assert!(path.exists());
let content = fs::read_to_string(&path).unwrap();
assert!(content.contains("pproxy 2.7.9 Strict Compatibility Report"));
let _ = fs::remove_file(&path);
let _ = fs::remove_dir(&dir);
}
#[test]
fn generate_strict_report_truncates_long_notes() {
let mut rec = default_record("long_notes");
rec.notes = "A".repeat(200);
rec.status = "drop_in".to_string();
let manifest = make_manifest(vec![rec]);
let report = generate_strict_report(&manifest);
assert!(report.contains("..."));
}
#[test]
fn module_existence_drop_in_structural_only_rejected() {
let mut rec = default_record("me_drop_struct");
rec.comparator = "module_existence".to_string();
rec.status = "drop_in".to_string();
rec.evidence_level = "structural_only".to_string();
let manifest = make_manifest(vec![rec]);
let errs = validate_strict_manifest(&manifest).unwrap_err();
assert!(
errs.errors.iter().any(|e| matches!(
e,
StrictValidationError::StructuralComparatorDropInRequiresEvidence { id, .. }
if id == "me_drop_struct"
)),
"expected StructuralComparatorDropInRequiresEvidence for module_existence + drop_in + structural_only"
);
}
#[test]
fn structural_only_with_drop_in_rejected() {
let mut rec = default_record("struct_drop");
rec.comparator = "protocol_wire".to_string();
rec.status = "drop_in".to_string();
rec.evidence_level = "structural_only".to_string();
let manifest = make_manifest(vec![rec]);
let errs = validate_strict_manifest(&manifest).unwrap_err();
assert!(
errs.errors.iter().any(|e| matches!(
e,
StrictValidationError::StructuralOnlyIncompatibleWithDropIn { id, .. }
if id == "struct_drop"
)),
"expected StructuralOnlyIncompatibleWithDropIn for structural_only + drop_in"
);
}
#[test]
fn drop_in_with_candidate_only_rejected() {
let mut rec = default_record("drop_candidate");
rec.comparator = "protocol_wire".to_string();
rec.status = "drop_in".to_string();
rec.evidence_level = "candidate_only".to_string();
let manifest = make_manifest(vec![rec]);
let errs = validate_strict_manifest(&manifest).unwrap_err();
assert!(
errs.errors.iter().any(|e| matches!(
e,
StrictValidationError::DropInRequiresStrongEvidence { id, .. }
if id == "drop_candidate"
)),
"expected DropInRequiresStrongEvidence for drop_in + candidate_only"
);
}
#[test]
fn drop_in_with_paired_oracle_passes() {
let mut rec = default_record("drop_paired");
rec.status = "drop_in".to_string();
rec.evidence_level = "paired_oracle".to_string();
let manifest = make_manifest(vec![rec]);
let result = validate_strict_manifest(&manifest);
assert!(result.is_ok(), "expected Ok, got {:?}", result.err());
}
#[test]
fn drop_in_with_bidirectional_interop_passes() {
let mut rec = default_record("drop_bidi");
rec.status = "drop_in".to_string();
rec.evidence_level = "bidirectional_interop".to_string();
let manifest = make_manifest(vec![rec]);
let result = validate_strict_manifest(&manifest);
assert!(result.is_ok(), "expected Ok, got {:?}", result.err());
}
#[test]
fn all_allowed_evidence_levels_are_valid() {
for ev in ALLOWED_EVIDENCE_LEVELS {
let mut rec = default_record(&format!("ev_{ev}"));
rec.evidence_level = ev.to_string();
rec.status = "gap".to_string();
rec.milestone = "F".to_string();
let manifest = make_manifest(vec![rec]);
let errs = validate_strict_manifest(&manifest);
if let Err(ref e) = errs {
assert!(
!e.errors
.iter()
.any(|e| matches!(e, StrictValidationError::UnknownEvidenceLevel { .. })),
"evidence_level \"{ev}\" should be valid"
);
}
}
}
#[test]
fn all_allowed_implementation_states_are_valid() {
for ist in ALLOWED_IMPLEMENTATION_STATES {
let mut rec = default_record(&format!("ist_{ist}"));
rec.implementation_state = ist.to_string();
rec.status = "gap".to_string();
rec.milestone = "F".to_string();
let manifest = make_manifest(vec![rec]);
let errs = validate_strict_manifest(&manifest);
if let Err(ref e) = errs {
assert!(
!e.errors.iter().any(|e| matches!(
e,
StrictValidationError::UnknownImplementationState { .. }
)),
"implementation_state \"{ist}\" should be valid"
);
}
}
}
#[test]
fn unknown_evidence_level_fails() {
let mut rec = default_record("bad_ev");
rec.evidence_level = "bogus".to_string();
let manifest = make_manifest(vec![rec]);
let errs = validate_strict_manifest(&manifest).unwrap_err();
assert!(
errs.errors.iter().any(|e| matches!(
e,
StrictValidationError::UnknownEvidenceLevel { value, .. } if value == "bogus"
)),
"expected UnknownEvidenceLevel"
);
}
#[test]
fn unknown_implementation_state_fails() {
let mut rec = default_record("bad_ist");
rec.implementation_state = "bogus".to_string();
let manifest = make_manifest(vec![rec]);
let errs = validate_strict_manifest(&manifest).unwrap_err();
assert!(
errs.errors.iter().any(|e| matches!(
e,
StrictValidationError::UnknownImplementationState { value, .. } if value == "bogus"
)),
"expected UnknownImplementationState"
);
}
#[test]
fn constant_value_drop_in_structural_only_rejected() {
let mut rec = default_record("cv_drop_struct");
rec.comparator = "constant_value".to_string();
rec.status = "drop_in".to_string();
rec.evidence_level = "structural_only".to_string();
let manifest = make_manifest(vec![rec]);
let errs = validate_strict_manifest(&manifest).unwrap_err();
assert!(
errs.errors.iter().any(|e| matches!(
e,
StrictValidationError::StructuralComparatorDropInRequiresEvidence { id, .. }
if id == "cv_drop_struct"
)),
"expected StructuralComparatorDropInRequiresEvidence for constant_value + drop_in + structural_only"
);
}
#[test]
fn gap_with_structural_only_passes() {
let mut rec = default_record("gap_struct");
rec.status = "gap".to_string();
rec.milestone = "F".to_string();
rec.evidence_level = "structural_only".to_string();
let manifest = make_manifest(vec![rec]);
let result = validate_strict_manifest(&manifest);
assert!(result.is_ok(), "expected Ok, got {:?}", result.err());
}
#[test]
fn rule_10a_structural_comparator_behavioral_scope_rejected() {
let mut rec = default_record("r10a_reject");
rec.comparator = "module_existence".to_string();
rec.status = "drop_in".to_string();
rec.certification_scope = "behavioral".to_string();
let manifest = make_manifest(vec![rec]);
let errs = validate_strict_manifest(&manifest).unwrap_err();
assert!(
errs.errors.iter().any(|e| matches!(
e,
StrictValidationError::StructuralComparatorBehavioralScopeMismatch { id, .. }
if id == "r10a_reject"
)),
"expected StructuralComparatorBehavioralScopeMismatch for module_existence + drop_in + behavioral"
);
}
#[test]
fn rule_10a_structural_comparator_structural_scope_passes() {
let mut rec = default_record("r10a_pass");
rec.comparator = "module_existence".to_string();
rec.status = "structural".to_string();
rec.certification_scope = "structural".to_string();
rec.behavior_record = Some("python.pproxy.server.Connection".to_string());
let manifest = make_manifest(vec![rec]);
let result = validate_strict_manifest(&manifest);
assert!(result.is_ok(), "expected Ok, got {:?}", result.err());
}
#[test]
fn rule_10b_closure_required_without_evidence_rejected() {
let mut rec = default_record("r10b_reject");
rec.closure_required = true;
rec.evidence_refs = vec![];
let manifest = make_manifest(vec![rec]);
let errs = validate_strict_manifest(&manifest).unwrap_err();
assert!(
errs.errors.iter().any(|e| matches!(
e,
StrictValidationError::ClosureRequiredWithoutEvidence { id, .. }
if id == "r10b_reject"
)),
"expected ClosureRequiredWithoutEvidence"
);
}
#[test]
fn rule_10b_closure_not_required_without_evidence_passes() {
let mut rec = default_record("r10b_pass");
rec.closure_required = false;
rec.evidence_refs = vec![];
let manifest = make_manifest(vec![rec]);
let result = validate_strict_manifest(&manifest);
assert!(result.is_ok(), "expected Ok, got {:?}", result.err());
}
#[test]
fn rule_10c_structural_missing_behavior_record_fails() {
let mut rec = default_record("r10c_reject");
rec.certification_scope = "structural".to_string();
rec.behavior_record = None;
rec.inventory_only = false;
let manifest = make_manifest(vec![rec]);
let errs = validate_strict_manifest(&manifest).unwrap_err();
assert!(
errs.errors.iter().any(|e| matches!(
e,
StrictValidationError::StructuralMissingBehaviorRecord { id, .. }
if id == "r10c_reject"
)),
"expected StructuralMissingBehaviorRecord"
);
}
#[test]
fn rule_10c_structural_inventory_only_passes() {
let mut rec = default_record("r10c_inventory_only");
rec.certification_scope = "structural".to_string();
rec.behavior_record = None;
rec.inventory_only = true;
let manifest = make_manifest(vec![rec]);
let result = validate_strict_manifest(&manifest);
assert!(result.is_ok(), "expected Ok, got {:?}", result.err());
}
#[test]
fn rule_10c_structural_with_behavior_record_passes() {
let mut rec = default_record("r10c_pass");
rec.certification_scope = "structural".to_string();
rec.behavior_record = Some("some.behavior.record".to_string());
let manifest = make_manifest(vec![rec]);
let result = validate_strict_manifest(&manifest);
assert!(result.is_ok(), "expected Ok, got {:?}", result.err());
}
#[test]
fn rule_10c_behavioral_scope_no_behavior_record_passes() {
let mut rec = default_record("r10c_behavioral_pass");
rec.certification_scope = "behavioral".to_string();
rec.behavior_record = None;
let manifest = make_manifest(vec![rec]);
let result = validate_strict_manifest(&manifest);
assert!(result.is_ok(), "expected Ok, got {:?}", result.err());
}
#[test]
fn unknown_certification_scope_fails() {
let mut rec = default_record("bad_scope");
rec.certification_scope = "bogus".to_string();
let manifest = make_manifest(vec![rec]);
let errs = validate_strict_manifest(&manifest).unwrap_err();
assert!(
errs.errors.iter().any(|e| matches!(
e,
StrictValidationError::UnknownCertificationScope { value, .. } if value == "bogus"
)),
"expected UnknownCertificationScope"
);
}
#[test]
fn all_allowed_certification_scopes_are_valid() {
for scope in ALLOWED_CERTIFICATION_SCOPES {
let mut rec = default_record(&format!("scope_{scope}"));
rec.certification_scope = scope.to_string();
rec.status = "gap".to_string();
rec.milestone = "F".to_string();
let manifest = make_manifest(vec![rec]);
let errs = validate_strict_manifest(&manifest);
if let Err(ref e) = errs {
assert!(
!e.errors.iter().any(|e| matches!(
e,
StrictValidationError::UnknownCertificationScope { .. }
)),
"certification_scope \"{scope}\" should be valid"
);
}
}
}
}