From 8e75b0873aeb17a0123d00ecc740471c0c6a31cd Mon Sep 17 00:00:00 2001 From: ScriptedAlchemy Date: Fri, 18 Sep 2026 10:29:52 +0000 Subject: [PATCH] fix(code-index): preserve deterministic text sizing evidence Text projection collapsed three different failures into BudgetExceeded: a real deadline, an unavailable reservation, and an indivisible batch whose record exceeds a fixed builder bound. The latter two lost their detail, and the background worker retried a deterministic refusal continuously while status could only say a read budget was exceeded. Keep deadline exhaustion as BudgetExceeded, retain reservation detail as unavailable, and project an indivisible batch or source-window overflow as a contract with its required and maximum bytes so convergence parks once and reports the actionable cause. --- .../src/code_index_scheduler/serving.rs | 20 ++++++++++++++++--- .../src/code_index_scheduler/tests/serving.rs | 15 +++++++++++--- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/crates/tracedecay-code-index-runtime/src/code_index_scheduler/serving.rs b/crates/tracedecay-code-index-runtime/src/code_index_scheduler/serving.rs index 814b5a6a6f..5d7ae15289 100644 --- a/crates/tracedecay-code-index-runtime/src/code_index_scheduler/serving.rs +++ b/crates/tracedecay-code-index-runtime/src/code_index_scheduler/serving.rs @@ -950,8 +950,17 @@ fn map_text_artifact_error(error: CodeLexicalArtifactErrorV1) -> RetrievalPortEr CodeLexicalArtifactErrorV1::Incompatible(_) => RetrievalPortError::IncompatibleProjection, CodeLexicalArtifactErrorV1::Contract(detail) => RetrievalPortError::Contract(detail), CodeLexicalArtifactErrorV1::Corrupt(detail) => RetrievalPortError::Contract(detail), - CodeLexicalArtifactErrorV1::Unreserved(_) - | CodeLexicalArtifactErrorV1::BatchTooLarge { .. } => RetrievalPortError::BudgetExceeded, + CodeLexicalArtifactErrorV1::Unreserved(detail) => RetrievalPortError::AuthorityUnavailable( + format!("lexical artifact reservation is unavailable: {detail}"), + ), + error @ CodeLexicalArtifactErrorV1::BatchTooLarge { .. } => { + // The builder has already tightened the source to one record + // before this mapping. The same record and fixed budget reproduce + // this refusal forever; calling it a request budget timeout made + // the background worker retry it as transient work and discarded + // the required/maximum evidence. + RetrievalPortError::Contract(error.to_string()) + } CodeLexicalArtifactErrorV1::Io(detail) | CodeLexicalArtifactErrorV1::Missing(detail) => { RetrievalPortError::AuthorityUnavailable(detail) } @@ -3751,7 +3760,12 @@ pub(super) fn text_artifact_builder_budget( build_memory_budget .checked_sub(source_window_bytes) .filter(|remaining| *remaining > 0) - .ok_or(RetrievalPortError::BudgetExceeded) + .ok_or_else(|| { + RetrievalPortError::Contract(format!( + "text-artifact source window needs {source_window_bytes} bytes, exhausting its \ + {build_memory_budget}-byte build reservation" + )) + }) } #[cfg(test)] diff --git a/crates/tracedecay-code-index-runtime/src/code_index_scheduler/tests/serving.rs b/crates/tracedecay-code-index-runtime/src/code_index_scheduler/tests/serving.rs index 19bba01627..82bc63a013 100644 --- a/crates/tracedecay-code-index-runtime/src/code_index_scheduler/tests/serving.rs +++ b/crates/tracedecay-code-index-runtime/src/code_index_scheduler/tests/serving.rs @@ -2750,7 +2750,11 @@ fn text_artifact_subdivision_yields_without_advancing_and_stops_at_one_chunk() { Err(tracedecay_query::retrieval::RetrievalPortError::Cancelled) ); } - Err(tracedecay_query::retrieval::RetrievalPortError::BudgetExceeded) => break, + Err(tracedecay_query::retrieval::RetrievalPortError::Contract(detail)) + if detail.contains("page batch exceeds") => + { + break; + } other => panic!("unexpected projection outcome: {other:?}"), } let slot = latest.text_projection_build.lock_slot(); @@ -2783,8 +2787,13 @@ fn source_window_and_builder_share_one_memory_reservation() { ); assert_eq!( super::super::text_artifact_builder_budget(ceiling, ceiling), - Err(tracedecay_query::retrieval::RetrievalPortError::BudgetExceeded), - "a source consuming the reservation must refuse before builder path access" + Err(tracedecay_query::retrieval::RetrievalPortError::Contract( + format!( + "text-artifact source window needs {ceiling} bytes, exhausting its \ + {ceiling}-byte build reservation" + ) + )), + "a source consuming the reservation must refuse with the reproducible sizing evidence" ); }