diff --git a/app/RSpade/Core/Manifest/_Manifest_Builder_Helper.php b/app/RSpade/Core/Manifest/_Manifest_Builder_Helper.php index aa7db12fa..99d321057 100755 --- a/app/RSpade/Core/Manifest/_Manifest_Builder_Helper.php +++ b/app/RSpade/Core/Manifest/_Manifest_Builder_Helper.php @@ -83,7 +83,7 @@ class _Manifest_Builder_Helper // This creates a map of className => filename (not full metadata to save space) // NOTE: Class override detection (rsx/ vs app/RSpade/) happens earlier in _check_unique_base_class_names() foreach (Manifest::$data['data']['files'] as $file => $filedata) { - if ($filedata['extension'] == $ext && !empty($filedata['class'])) { + if (isset($filedata['extension']) && $filedata['extension'] == $ext && !empty($filedata['class'])) { $class_name = $filedata['class']; // Duplicates should have been caught by _check_unique_base_class_names() diff --git a/app/RSpade/Core/Manifest/_Manifest_Quality_Helper.php b/app/RSpade/Core/Manifest/_Manifest_Quality_Helper.php index f1d64757f..c9f6c6f1e 100755 --- a/app/RSpade/Core/Manifest/_Manifest_Quality_Helper.php +++ b/app/RSpade/Core/Manifest/_Manifest_Quality_Helper.php @@ -310,21 +310,32 @@ class _Manifest_Quality_Helper // Valid override: exactly one file in rsx/, rest in app/RSpade/ if (count($rsx_files) === 1 && count($framework_files) >= 1) { + $did_change = false; // Rename framework files to .upstream and remove from manifest foreach ($framework_files as $framework_file) { $full_framework_path = base_path($framework_file); $upstream_path = $full_framework_path . '.upstream'; if (file_exists($full_framework_path) && !file_exists($upstream_path)) { + // Normal case: rename to .upstream rename($full_framework_path, $upstream_path); console_debug('MANIFEST', "Class override: {$class_name} - moved {$framework_file} to .upstream"); + $did_change = true; + } elseif (file_exists($full_framework_path) && file_exists($upstream_path)) { + // Self-healing: both .php and .php.upstream exist (e.g., after framework update) + // Remove the .php file since .upstream is the correct archived version + unlink($full_framework_path); + console_debug('MANIFEST', "Class override: {$class_name} - removed duplicate {$framework_file} (upstream already exists)"); + $did_change = true; } // Remove from manifest data so it won't be indexed unset(Manifest::$data['data']['files'][$framework_file]); } - Manifest::$_needs_manifest_restart = true; + if ($did_change) { + Manifest::$_needs_manifest_restart = true; + } continue; } diff --git a/app/RSpade/Core/Manifest/_Manifest_Scanner_Helper.php b/app/RSpade/Core/Manifest/_Manifest_Scanner_Helper.php index 8b5e31ccf..6c5218166 100755 --- a/app/RSpade/Core/Manifest/_Manifest_Scanner_Helper.php +++ b/app/RSpade/Core/Manifest/_Manifest_Scanner_Helper.php @@ -168,8 +168,8 @@ class _Manifest_Scanner_Helper $current_size = filesize($absolute_path); - // Stage 1: Size check - if ($old['size'] != $current_size) { + // Stage 1: Size check (guard for incomplete manifest entries) + if (!isset($old['size']) || $old['size'] != $current_size) { // Only show the message once per page load if (!Manifest::$__shown_rescan_message) { console_debug('MANIFEST', '* File ' . $file . ' has changed size, triggering manifest rescan *'); @@ -180,9 +180,9 @@ class _Manifest_Scanner_Helper return true; } - // Stage 2: mtime check + // Stage 2: mtime check (guard for incomplete manifest entries) $current_mtime = filemtime($absolute_path); - if ($old['mtime'] != $current_mtime) { + if (!isset($old['mtime']) || $old['mtime'] != $current_mtime) { // Only show the message once per page load if (!Manifest::$__shown_rescan_message) { console_debug('MANIFEST', '* File ' . $file . ' has changed mtime, triggering manifest rescan *');