From 9a1838a32b77740f787a7a097af294842ed9cfdd Mon Sep 17 00:00:00 2001 From: nsfisis Date: Fri, 24 Jul 2026 20:23:28 +0900 Subject: fix(solver-problems): compare RULE_LEARNED sort keys like PHP's <=> Problem::getPrettyString sorts same-priority reasons by getSortableString(), whose RULE_LEARNED key is a '-'-joined literal id string (e.g. "-95"). PHP's <=> compares two numeric strings numerically, but the port used plain String::cmp (byte-wise), which reverses relative order for same-length negative-number keys. Added shirabe_php_shim::loosely_compare to approximate PHP's <=> for this pattern (numeric compare when both sides parse as numbers, else byte compare) and switched the sort comparator to use it. The diagnosis this replaces (from the commit being amended) blamed Pool package-id assignment order diverging from PHP under COMPOSER_POOL_OPTIMIZER=0. That was disproven this session: direct instrumentation of both PHP and the Rust port confirmed identical relative package-id order, including on the ~335-package github-issues-7665 fixture (ids matched up to a constant +2 offset from a platform-mock package count difference). The sort comparator was the actual bug, not package loading order. Co-Authored-By: Claude Sonnet 5 --- crates/shirabe/src/dependency_resolver/problem.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'crates/shirabe/src') diff --git a/crates/shirabe/src/dependency_resolver/problem.rs b/crates/shirabe/src/dependency_resolver/problem.rs index 5ff949a9..a2072372 100644 --- a/crates/shirabe/src/dependency_resolver/problem.rs +++ b/crates/shirabe/src/dependency_resolver/problem.rs @@ -13,9 +13,9 @@ use indexmap::IndexMap; use shirabe_external_packages::composer::pcre::{CaptureKey, Preg}; use shirabe_external_packages::symfony::console::formatter::OutputFormatter; use shirabe_php_shim::{ - LogicException, PhpMixed, defined, extension_loaded, implode, in_array, php_regex, phpversion, - spl_object_hash, sprintf, str_replace, str_starts_with, stripos, strpos, strtolower, substr, - substr_count, version_compare, + LogicException, PhpMixed, defined, extension_loaded, implode, in_array, loosely_compare, + php_regex, phpversion, spl_object_hash, sprintf, str_replace, str_starts_with, stripos, strpos, + strtolower, substr, substr_count, version_compare, }; use shirabe_semver::constraint::AnyConstraint; use shirabe_semver::constraint::MultiConstraint; @@ -119,8 +119,13 @@ impl Problem { return rule2_prio.cmp(&rule1_prio); } - self.get_sortable_string(pool, &rule1.borrow()) - .cmp(&self.get_sortable_string(pool, &rule2.borrow())) + // PHP: getSortableString(...) <=> getSortableString(...). RULE_LEARNED keys are + // '-'-joined literal ids (e.g. "-95"), which PHP's <=> compares numerically when both + // sides are numeric strings rather than byte-by-byte. + loosely_compare( + &self.get_sortable_string(pool, &rule1.borrow()), + &self.get_sortable_string(pool, &rule2.borrow()), + ) }); Self::format_deduplicated_rules( -- cgit v1.3.1