///|
/// A reviewable operational contract derived from a measurement plan.
pub(all) struct MeasurementProtocol {
part_id : String
revision : String
step_count : Int
sample_count : Int
duration_seconds : Double
preconditions : Array[String]
acceptance_checks : Array[String]
warnings : Array[String]
}
///|
fn protocol_preconditions(plan : MeasurementPlan) -> Array[String] {
let result = [
"instrument calibration is current", "part coordinate system is established",
"ambient temperature is recorded",
]
if plan.steps.length() > 0 {
result.push("all planned devices are available")
} else {
result.push("at least one measurable feature is required")
}
result
}
///|
fn protocol_acceptance_checks(plan : MeasurementPlan) -> Array[String] {
let result = [
"every feature has a deterministic measurement step", "observations are checked against feature limits",
"the final report preserves feature and device identifiers",
]
if plan.summary.capability {
result.push("device uncertainty is within feature tolerance")
} else {
result.push("review capability warnings before release")
}
result
}
///|
/// Build an auditable protocol from the selected plan.
pub fn protocol_from_plan(
plan : MeasurementPlan,
revision : String,
) -> MeasurementProtocol {
let metrics = plan_metrics(plan)
{
part_id: plan.part_id,
revision,
step_count: metrics.step_count,
sample_count: metrics.estimated_samples,
duration_seconds: metrics.estimated_seconds,
preconditions: protocol_preconditions(plan),
acceptance_checks: protocol_acceptance_checks(plan),
warnings: plan.summary.warnings,
}
}
///|
/// Validate protocol metadata before it is exported or executed.
pub fn validate_protocol(protocol : MeasurementProtocol) -> Array[String] {
let issues = []
if protocol.revision.trim() == "" {
issues.push("protocol revision is required")
}
if protocol.part_id.trim() == "" {
issues.push("part identifier is required")
}
if protocol.step_count <= 0 {
issues.push("protocol must contain at least one step")
}
if protocol.sample_count < protocol.step_count {
issues.push("sample count cannot be below step count")
}
if protocol.duration_seconds <= 0.0 {
issues.push("duration estimate must be positive")
}
if protocol.preconditions.length() < 3 {
issues.push("protocol preconditions are incomplete")
}
issues
}
///|
/// Return whether a protocol is ready for a downstream consumer.
pub fn protocol_accepts(protocol : MeasurementProtocol) -> Bool {
validate_protocol(protocol).length() == 0 && protocol.warnings.length() == 0
}
///|
/// Classify protocol readiness for risk dashboards.
pub fn protocol_risk(protocol : MeasurementProtocol) -> String {
let issue_count = validate_protocol(protocol).length() +
protocol.warnings.length()
if issue_count == 0 {
"low"
} else if issue_count < 3 {
"medium"
} else {
"high"
}
}
///|
fn protocol_line(label : String, value : String) -> String {
label + ": " + value + "\n"
}
///|
/// Render a stable text representation suitable for an audit attachment.
pub fn protocol_text(protocol : MeasurementProtocol) -> String {
let mut result = ""
result = result + protocol_line("part", protocol.part_id)
result = result + protocol_line("revision", protocol.revision)
result = result + protocol_line("steps", protocol.step_count.to_string())
result = result + protocol_line("samples", protocol.sample_count.to_string())
result = result +
protocol_line("seconds", protocol.duration_seconds.to_string())
result = result + "preconditions:\n"
for item in protocol.preconditions {
result = result + "- " + item + "\n"
}
result = result + "acceptance:\n"
for item in protocol.acceptance_checks {
result = result + "- " + item + "\n"
}
if protocol.warnings.length() > 0 {
result = result + "warnings:\n"
for item in protocol.warnings {
result = result + "- " + item + "\n"
}
}
result
}
///|
/// Return the number of acceptance checks that are available.
pub fn protocol_check_count(protocol : MeasurementProtocol) -> Int {
protocol.acceptance_checks.length()
}
///|
/// Return whether the protocol has a complete operational envelope.
pub fn protocol_is_operational(protocol : MeasurementProtocol) -> Bool {
protocol.preconditions.length() >= 4 &&
protocol.acceptance_checks.length() >= 4 &&
protocol.duration_seconds > 0.0
}
///|
/// Return a compact protocol status for command-line reporting.
pub fn protocol_status(protocol : MeasurementProtocol) -> String {
if protocol_accepts(protocol) {
"ready"
} else if protocol_risk(protocol) == "high" {
"blocked"
} else {
"review"
}
}