From c369cbe4b12b563eb8a5d4419e6e0ed729721137 Mon Sep 17 00:00:00 2001 From: Puma Date: Sat, 3 Oct 2026 08:06:30 -0700 Subject: [PATCH] refactor(registry): box private selection diagnostic errors --- .github/workflows/quality-gates.yml | 2 + .../src/runtime_selection_policy.rs | 51 +++++++++++++++---- .../src/technical_fit_tests.rs | 9 ++++ ...0-03-runtime-registry-diagnostic-errors.md | 7 +++ 4 files changed, 58 insertions(+), 11 deletions(-) create mode 100644 docs/plans/domain-architecture-and-multimodal/reports/2026-10-03-runtime-registry-diagnostic-errors.md diff --git a/.github/workflows/quality-gates.yml b/.github/workflows/quality-gates.yml index 52fb41d4b..2edc2cb9d 100644 --- a/.github/workflows/quality-gates.yml +++ b/.github/workflows/quality-gates.yml @@ -251,6 +251,8 @@ jobs: - name: Run workflow-nodes tests run: cargo test -p workflow-nodes --lib + - name: Run runtime registry contract tests + run: cargo test -p pantograph-runtime-registry - name: Run task summary contract tests run: | cargo test -p pantograph-workflow-service --lib workflow::task_run_summary::tests:: -- --list > "$RUNNER_TEMP/task-summary-tests.list" diff --git a/crates/pantograph-runtime-registry/src/runtime_selection_policy.rs b/crates/pantograph-runtime-registry/src/runtime_selection_policy.rs index 2eb78250f..a696b5284 100644 --- a/crates/pantograph-runtime-registry/src/runtime_selection_policy.rs +++ b/crates/pantograph-runtime-registry/src/runtime_selection_policy.rs @@ -178,7 +178,7 @@ pub(crate) fn select_runtime_technical_fit_automatically( return RuntimeSelectionDecision::new(unselected_decision_with_device_diagnostics( RuntimeTechnicalFitSelectionMode::Automatic, Vec::new(), - vec![diagnostic], + vec![*diagnostic], )); } }; @@ -292,7 +292,7 @@ fn automatic_selection_policy_trace( controlled_exploration_seed_basis: Option<&str>, history_threshold_state: RuntimeTechnicalFitHistoryThresholdState, history_ranking_enabled: bool, -) -> Result { +) -> Result> { let candidate_set_summary = automatic_candidate_set_summary(request, eligible_candidates)?; Ok(RuntimeTechnicalFitSelectionPolicyTrace { policy_version: TECHNICAL_FIT_SELECTION_POLICY_VERSION, @@ -327,12 +327,12 @@ fn automatic_selection_policy_trace( fn automatic_candidate_set_summary( request: &RuntimeTechnicalFitRequest, eligible_candidates: &[&RuntimeTechnicalFitCandidate], -) -> Result { +) -> Result> { let total_candidate_count = checked_candidate_count(request.candidates.len())?; let eligible_candidate_count = checked_candidate_count(eligible_candidates.len())?; let rejected_candidate_count = total_candidate_count .checked_sub(eligible_candidate_count) - .ok_or_else(candidate_summary_count_diagnostic)?; + .ok_or_else(|| Box::new(candidate_summary_count_diagnostic()))?; Ok(RuntimeTechnicalFitCandidateSetSummary { total_candidate_count, @@ -346,8 +346,8 @@ fn automatic_candidate_set_summary( .normalized()) } -fn checked_candidate_count(count: usize) -> Result { - u32::try_from(count).map_err(|_| candidate_summary_count_diagnostic()) +fn checked_candidate_count(count: usize) -> Result> { + u32::try_from(count).map_err(|_| Box::new(candidate_summary_count_diagnostic())) } fn candidate_summary_count_diagnostic() -> RuntimeTechnicalFitDeviceDiagnostic { @@ -822,7 +822,7 @@ fn resource_budget_diagnostic( }; let reserved_bytes = match active_reserved_bytes(runtime_snapshot, resource_kind) { Ok(reserved_bytes) => reserved_bytes, - Err(diagnostic) => return Some(diagnostic_context_from_candidate(diagnostic, candidate)), + Err(diagnostic) => return Some(diagnostic_context_from_candidate(*diagnostic, candidate)), }; let Some(available_bytes) = after_safety_margin_bytes.checked_sub(reserved_bytes) else { return Some(resource_budget_underflow_diagnostic( @@ -871,7 +871,7 @@ fn resource_budget_diagnostic( fn active_reserved_bytes( runtime_snapshot: &RuntimeRegistryRuntimeSnapshot, resource_kind: RuntimeAdmissionResourceKind, -) -> Result { +) -> Result> { let mut reserved_bytes = 0_u64; for active_claim in &runtime_snapshot.active_reservation_claims { for claim in active_claim @@ -891,10 +891,10 @@ fn checked_add_claim_bytes( resource_kind: RuntimeAdmissionResourceKind, reserved_bytes: u64, claim: &RuntimeReservationResourceClaim, -) -> Result { +) -> Result> { reserved_bytes .checked_add(claim.bytes) - .ok_or_else(|| RuntimeTechnicalFitDeviceDiagnostic { + .ok_or_else(|| Box::new(RuntimeTechnicalFitDeviceDiagnostic { code: RuntimeTechnicalFitDeviceDiagnosticCode::ResourceAccountingOverflow, severity: RuntimeTechnicalFitDeviceDiagnosticSeverity::Error, message: format!( @@ -911,7 +911,7 @@ fn checked_add_claim_bytes( model_id: None, evidence_key: Some(resource_kind.resource_label().to_string()), requested_runtime_key: None, - }) + })) } fn resource_budget_underflow_diagnostic( @@ -1132,3 +1132,32 @@ fn candidate_has_available_peak_memory_estimate(candidate: &RuntimeTechnicalFitC && estimate.value_bytes().is_some() }) } + +#[cfg(test)] +mod private_diagnostic_tests { + use super::checked_candidate_count; + + #[test] + fn candidate_counts_preserve_exact_valid_boundaries() { + assert_eq!(checked_candidate_count(0).unwrap(), 0); + assert_eq!( + checked_candidate_count(u32::MAX as usize).unwrap(), + u32::MAX + ); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn candidate_count_overflow_preserves_exact_diagnostic_json() { + let diagnostic = checked_candidate_count(u32::MAX as usize + 1).unwrap_err(); + let expected = serde_json::json!({ + "code": "no_valid_candidate", + "severity": "error", + "message": "technical-fit candidate set is too large to summarize exactly" + }); + assert_eq!(serde_json::to_value(diagnostic.as_ref()).unwrap(), expected); + let decoded: crate::technical_fit::RuntimeTechnicalFitDeviceDiagnostic = + serde_json::from_value(expected).unwrap(); + assert_eq!(*diagnostic, decoded); + } +} diff --git a/crates/pantograph-runtime-registry/src/technical_fit_tests.rs b/crates/pantograph-runtime-registry/src/technical_fit_tests.rs index 33fb0bc60..ad0971b37 100644 --- a/crates/pantograph-runtime-registry/src/technical_fit_tests.rs +++ b/crates/pantograph-runtime-registry/src/technical_fit_tests.rs @@ -2563,6 +2563,15 @@ fn selector_reports_resource_accounting_overflow_before_selection() { assert_eq!(decision.selected_candidate_id, None); assert_eq!(decision.device_diagnostics.len(), 1); + assert_eq!(serde_json::to_value(&decision.device_diagnostics[0]).unwrap(), serde_json::json!({ + "code": "resource_accounting_overflow", + "severity": "error", + "message": "technical-fit resource accounting overflowed while summing active ram_bytes claims for runtime 'runtime-overflow'", + "runtime_id": "runtime-overflow", + "backend_key": "pytorch", + "evidence_key": "ram_bytes", + "requested_runtime_key": "pytorch" + })); assert_eq!( decision.device_diagnostics[0].code, RuntimeTechnicalFitDeviceDiagnosticCode::ResourceAccountingOverflow diff --git a/docs/plans/domain-architecture-and-multimodal/reports/2026-10-03-runtime-registry-diagnostic-errors.md b/docs/plans/domain-architecture-and-multimodal/reports/2026-10-03-runtime-registry-diagnostic-errors.md new file mode 100644 index 000000000..345a7a049 --- /dev/null +++ b/docs/plans/domain-architecture-and-multimodal/reports/2026-10-03-runtime-registry-diagnostic-errors.md @@ -0,0 +1,7 @@ +# Private runtime selection diagnostic errors + +Fresh PR #39 aggregate Clippy clears workflow-service and stops at five private runtime-registry Result paths whose error is the same 224-byte RuntimeTechnicalFitDeviceDiagnostic DTO. Box only these errors in automatic_selection_policy_trace, automatic_candidate_set_summary, checked_candidate_count, active_reserved_bytes and checked_add_claim_bytes. Unwrap at the existing automatic decision-vector and resource-budget context adapters. Preserve public signatures, the raw DTO, diagnostic fields/JSON, ranking/accounting decisions and success values. + +Boundary tests retain zero/u32-max candidate counts and exact overflow diagnostic JSON (the usize overflow case is explicitly a 64-bit test). The existing public selector resource-overflow test now checks the entire contextualized payload, while full registry tests retain successful selection, budget and underflow behavior. Only failing paths add a box allocation. No broad Result or public layout change is made. + +Root approved this bounded registry branch using the existing checkout. Root source review accepted all four files at frozen tree e88e208b5567da1dda64974dd1c65bb4524d5801. Hosted full-crate/aggregate qualification remains pending; no local Rust execution is claimed.