From fa7a980418ef99d772e67c66c28dfa7b5181f875 Mon Sep 17 00:00:00 2001 From: "sorokin.oleg.edu" Date: Thu, 24 Sep 2026 17:28:48 -0700 Subject: [PATCH] Retain only source backing guard after exact policy transfer --- .../src/language/analysis_source/mixed.rs | 4 +- .../language/analysis_source/mixed/carried.rs | 50 +++++++++++++------ .../analysis_source/mixed/carried/tests.rs | 11 +++- ...s-carried-phase-implementation-20260925.md | 10 ++++ 4 files changed, 56 insertions(+), 19 deletions(-) diff --git a/crates/oa-core/src/language/analysis_source/mixed.rs b/crates/oa-core/src/language/analysis_source/mixed.rs index c59cdb5d..8c822750 100644 --- a/crates/oa-core/src/language/analysis_source/mixed.rs +++ b/crates/oa-core/src/language/analysis_source/mixed.rs @@ -47,7 +47,7 @@ pub(super) struct ParsedMixedSyntax<'s> { // phase adds syntax entries to this once, not tokens/positions again. metadata: usize, // Kept through consumed resolution/indexing; fixes the live backing owner. - carried: Option>, + carried: Option>, } struct FileSyntax<'s> { @@ -257,7 +257,7 @@ fn parse_impl<'s>( bundle: &'s SourceBundle, limits: ProjectLimits, profile: Limits, - carried: Option>, + carried: Option>, ) -> Result, Vec> { let entry_source = bundle.files.get(&bundle.entry).map_or("", String::as_str); let at_entry = |error| located(&bundle.entry, entry_source, ordinary_error(error)); diff --git a/crates/oa-core/src/language/analysis_source/mixed/carried.rs b/crates/oa-core/src/language/analysis_source/mixed/carried.rs index bbc04821..357c077f 100644 --- a/crates/oa-core/src/language/analysis_source/mixed/carried.rs +++ b/crates/oa-core/src/language/analysis_source/mixed/carried.rs @@ -26,23 +26,44 @@ enum SnapshotBacking<'s> { pub(super) struct CarriedInput<'s> { backing: SnapshotBacking<'s>, } +enum GuardBacking<'s> { + Borrowed, + Retained(&'s RetainedSnapshot), +} + +/// Policy has transferred into Budget/ParsedMixedSyntax. Only backing ownership +/// remains here, avoiding a duplicate inline policy in every later witness. +pub(super) struct CarriedGuard<'s> { + backing: GuardBacking<'s>, +} impl<'s> CarriedInput<'s> { - fn policy(&self) -> &SnapshotPolicy { - match &self.backing { - SnapshotBacking::Borrowed { policy, .. } => policy, - SnapshotBacking::Retained(owner) => &owner.policy, - } - } - fn bundle(&self) -> &'s SourceBundle { - match &self.backing { - SnapshotBacking::Borrowed { bundle, .. } => bundle, - SnapshotBacking::Retained(owner) => &owner.bundle, + fn into_parts(self) -> (&'s SourceBundle, SnapshotPolicy, CarriedGuard<'s>) { + match self.backing { + SnapshotBacking::Borrowed { bundle, policy } => ( + bundle, + policy, + CarriedGuard { + backing: GuardBacking::Borrowed, + }, + ), + SnapshotBacking::Retained(owner) => ( + &owner.bundle, + SnapshotPolicy { + limits: owner.policy.limits, + project_limits: owner.policy.project_limits, + }, + CarriedGuard { + backing: GuardBacking::Retained(owner), + }, + ), } } +} +impl CarriedGuard<'_> { pub(super) fn slots(&self) -> Slots { match &self.backing { - SnapshotBacking::Borrowed { .. } => Slots::default(), - SnapshotBacking::Retained(owner) => owner.retained, + GuardBacking::Borrowed => Slots::default(), + GuardBacking::Retained(owner) => owner.retained, } } pub(super) fn check( @@ -63,9 +84,8 @@ impl<'s> CarriedInput<'s> { /// Input already binds the actual bundle; callers cannot supply a replacement. fn parse_carried(input: CarriedInput<'_>) -> Result, Vec> { - let bundle = input.bundle(); - let policy = input.policy(); - parse_impl(bundle, policy.project_limits, policy.limits, Some(input)) + let (bundle, policy, guard) = input.into_parts(); + parse_impl(bundle, policy.project_limits, policy.limits, Some(guard)) } #[cfg(test)] diff --git a/crates/oa-core/src/language/analysis_source/mixed/carried/tests.rs b/crates/oa-core/src/language/analysis_source/mixed/carried/tests.rs index 72516aaf..474b22ec 100644 --- a/crates/oa-core/src/language/analysis_source/mixed/carried/tests.rs +++ b/crates/oa-core/src/language/analysis_source/mixed/carried/tests.rs @@ -139,7 +139,7 @@ fn real_retained_bundles_keep_exact_guard_work_and_once_only_resolved_baseline() assert_eq!(parsed.budget.numeric_units(), 0); assert!(std::ptr::eq(parsed.bundle, &owner.bundle)); assert!( - matches!(&parsed.carried.as_ref().unwrap().backing,SnapshotBacking::Retained(retained) if std::ptr::eq(*retained,&owner)) + matches!(&parsed.carried.as_ref().unwrap().backing,GuardBacking::Retained(retained) if std::ptr::eq(*retained,&owner)) ); let resolved = project::resolve(parsed).unwrap(); assert_eq!(resolved.project(), &expected_project()); @@ -320,12 +320,19 @@ fn explicit_fault_injections_cover_occurrence_caps_and_unreachable_overflows() { let budget = Budget::new(profile(100, 1024)).unwrap(); // Valid hard limits reject C first: direct injection reaches arithmetic. assert_eq!( - held.input().check(&budget, 0, 1).unwrap_err().message, + held.input() + .into_parts() + .2 + .check(&budget, 0, 1) + .unwrap_err() + .message, "Mixed auxiliary storage size overflow." ); held.retained = Slots::default(); assert_eq!( held.input() + .into_parts() + .2 .check(&budget, usize::MAX, 1) .unwrap_err() .message, diff --git a/harness/analysis-carried-phase-implementation-20260925.md b/harness/analysis-carried-phase-implementation-20260925.md index 5b5162f1..b0857e39 100644 --- a/harness/analysis-carried-phase-implementation-20260925.md +++ b/harness/analysis-carried-phase-implementation-20260925.md @@ -19,3 +19,13 @@ Zero carried mode intentionally refuses E cap 11 at preprojection, while legacy No Cargo/build/test execution was performed by the implementation agent. Targeted rustfmt on owned files and raw-LF normalization are authoring checks only. Parent owns source review integration, exact-source commits, compiler/focused/full-suite gates and publication. Inherited full-suite failures and formatting issues are not addressed by this patch; parent gates will compare actual outcomes. The documented environment-sensitive upstream stack observation remains a limitation. Existing small-stack controls were not edited or waived. Independent test-source review corrected two pre-execution fixture mistakes: use the accepted oa_property/sa_property keywords, and distinguish the parser include-edge error span 0..1 from the traversal include-depth span 0..23. These are source-review corrections, not recorded runtime failures. + +## Recorded regression and slim-guard candidate + +Parent's `d11b99bb` focused run passed all 12 carried tests, but its full run aborted at the unchanged `ordinary_index::tests::small_stack_success_and_late_header_failure_leave_no_partial_owner` with STATUS_STACK_OVERFLOW. The predecessor `18073a6f` full run had completed with 230 passing tests and 16 inherited failures, including that control. This is a failed current full gate, not an inherited-failure waiver or an accepted repair. + +The exact-artifact LLDB trace reproduces the overflow during Windows heap allocation under formatting/Exact::parse_decimal, then exact_literal, syntax::binding, declarations::parse, State::parse_typed, Parser::unit, new parse_impl, parse_with_profile, parse, accepted/indexed helpers and the existing worker. The diagnostic child's killed exit is not a test pass. Parent measured individual prologues of parse_impl 11,144 bytes, parse_with_profile 312, accepted 1,752, indexed 1,704 and worker 7,752; these are not the complete active stack. Raw evidence remains in the parent gate records, including `carried-debugger-d11b99b-1.log` and `carried-full-d11b99b-1.stack-frames.json`. + +The selected narrow candidate consumes CarriedInput before entering the shared parser. Exact captured policy transfers into Budget and syntax.limits; the retained CarriedGuard holds only Borrowed or Retained(&RetainedSnapshot). This removes the duplicate inline SnapshotPolicy payload from parsed/resolved/indexed/result carriers, while retained backing still borrows the actual allocation-owning bundle. Borrowed source identity remains bound through ParsedMixedSyntax.bundle. Explicit Some mode still distinguishes carried zero from legacy None, and all checks/reservations/Usage remain unchanged. No heap allocation or new logical storage was introduced. The parser wrapper remains uninlined and unchanged. + +Only carried tests' guard-shape inspection and direct injected-arithmetic access follow the new internal guard type; all expected counts, limits, spans, outcomes and existing stack tests remain unchanged. The candidate is not claimed to establish a sole overflow cause or a successful repair before parent exact-source gates. All original failure evidence remains retained.