aboutsummaryrefslogtreecommitdiffhomepage
AgeCommit message (Collapse)Author
2026-06-06feat(repository-utils): recurse into transitive dependenciesnsfisis
Implement the self-recursion in filterRequiredPackages so that packages required transitively are collected, matching the PHP source. BasePackageHandle is a type alias for PackageInterfaceHandle, so no cast is needed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06feat(package-repository): filter advisories by affected version constraintnsfisis
Implement the previously stubbed phase-b TODO so getSecurityAdvisories skips advisories whose affected_versions do not match the requested package constraint. Share the package VersionParser with PartialSecurityAdvisory::create across both PackageRepository and ComposerRepository instead of a separate semver parser instance. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06refactor(installed-repository): make add_repository infallible with assertnsfisis
The repository type check was an internal invariant, not a recoverable error condition. Replace the Result-returning validation with an assert!, matching Composer's design where add_repository throws only on a programming error, and drop the now-unneeded error handling at call sites. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06feat(composite-repository): forward remove_package to writable reposnsfisis
Resolve the phase-b TODO by adding an as_writable_repository_interface_mut downcast helper on RepositoryInterface, mirroring PHP's instanceof WritableRepositoryInterface check, and propagate inner errors.
2026-06-06refactor(command): share Input/OutputInterface via Rc<RefCell>nsfisis
Convert InputInterface and OutputInterface parameters from &dyn/&mut dyn references to Rc<RefCell<dyn ...>> shared ownership across the command, console, and IO layers, matching the Phase C shared-ownership approach already used for IOInterface. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06refactor(version-bumper): share caller's VersionParser with ArrayLoadernsfisis
Mirror PHP's "new ArrayLoader($parser)" by passing the existing parser instead of None. VersionParser is stateless, so behavior is unchanged; this drops the phase-b TODO. Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
2026-06-06fix(json-loader): pass decoded config to loader instead of empty mapnsfisis
The Phase B stub discarded the decoded PhpMixed and handed an empty IndexMap to LoaderInterface::load, so nothing was actually loaded. Unbox PhpMixed::Array into the map; mirror PHP's array $config type juggling by raising a TypeError for non-array decode results. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06refactor(operation,link): port __toString to Displaynsfisis
Move __toString ports to std::fmt::Display: convert Link's inherent to_string() and make OperationInterface require Display instead of a to_string() method, with each operation implementing Display. Also fix the operation __toString output to use show(false), matching SolverOperation::__toString() (was show(true)). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06refactor(link): drop phase-b shared-ownership TODOnsfisis
Link is an immutable value object and is never compared by reference identity, so cloning its fields is faithful to PHP. The shared-ownership TODO does not apply. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06fix(array-dumper): emit package links and require Link pretty constraintnsfisis
Resolve the phase-b TODO that left the supported-link-types loop as dead code (links were always an empty Vec), so requires/conflicts/provides/ replaces/require-dev are dumped again via PackageInterface::get_links_for_type, matching the PHP magic-call loop. Every Link in production is constructed with a pretty constraint (all ArrayLoader/AliasPackage/PlatformRepository/InstalledRepository sites pass one), so make Link::pretty_constraint a required String instead of Option<String>. get_pretty_constraint() now returns &str directly rather than anyhow::Result<&str>, dropping the unreachable UnexpectedValueException guard, and all call sites are updated. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06fix(base-package): move equals to PackageInterfaceHandle for reference identitynsfisis
PHP BasePackage::equals uses === (reference identity), unwrapping AliasPackage on both sides first. A plain &self / &dyn PackageInterface cannot express this, so implement it on the shared handle where the Rc-based identity infrastructure (as_alias, get_alias_of, ptr_eq) already lives, and drop the unimplementable trait stub. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06refactor(archiver): yield PathBuf from ArchivableFilesFinder, drop SplFileInfonsfisis
Migrate ArchivableFilesFinder off Symfony's SplFileInfo onto Path/PathBuf, resolving the phar_archiver TODO(phase-b) that required a .map() adapter to bridge SplFileInfo -> PathBuf. - ArchivableFilesFinder now yields PathBuf; accept() takes &Path; the exclude closure receives &Path and uses Path::canonicalize / is_symlink. The SplFileInfo -> PathBuf conversion happens once at the symfony get_iterator boundary (get_iterator stays SplFileInfo for cache.rs). - symfony Finder::filter callback changed to FnMut(&Path) (sole caller is the finder). - PharArchiver passes the finder straight into ArchivableFilesFilter, mirroring PHP's new ArchivableFilesFilter($files). - ZipArchiver consumes PathBuf items, computing the relative path via strip_prefix(sources) in place of SplFileInfo::getRelativePathname. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06fix(self-update-command): resolve finder-related phase-b TODOsnsfisis
- Add Display for SplFileInfo (PHP (string) cast -> getPathname) and use it in clean_backups instead of a debug-format placeholder. - Generalize iterator_to_array's signature to preserve the element type so get_last_backup_version collects real SplFileInfo and returns the last basename, instead of mapping every entry to PhpMixed::Null. - Drop the stale builder-restructure TODO in get_old_installation_finder. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06feat(archivable-files-finder): wire exclude closure into Finder::filternsfisis
Add a Finder::filter(Box<dyn FnMut(&SplFileInfo) -> bool>) stub method and route the exclude closure through it, matching PHP's ->in()->filter() chain. FnMut faithfully represents PHP's stateful \Closure. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06fix(vcs-downloader): abort on local changes in parent cleanChanges pathnsfisis
The VcsDownloaderBase::clean_changes stub returned Ok(None), silently swallowing the abort that PHP's parent::cleanChanges() raises when the working copy has uncommitted changes. Drop the stub and give Git/Svn a private fail_on_local_changes helper that performs the getLocalChanges check and throws, matching the default VcsDownloader::clean_changes(). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06refactor(solver-problems): pass reasons IndexMap directly to ↵nsfisis
get_extension_problems PHP's getExtensionProblems receives getReasons() directly; match that instead of materializing an intermediate Vec<Vec<...>> with Rc clones. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06feat(rule-set): render rule pretty strings via Rule::get_pretty_stringnsfisis
Resolve the phase-b stub by threading repository set, request and a mutable pool into Rule::getPrettyString, mirroring PHP's default empty installedMap/learnedPool arguments. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06fix(pool-optimizer): assert irremovable invariant instead of swallowingnsfisis
mark_package_for_removal's LogicException can only fire on a bug since both callers pre-filter irremovable packages, so port it as an assert! rather than a recoverable Result. This unwinds the Result chain through optimize and drops the pool_builder match that silently returned the unoptimized pool on error, matching PHP's fatal-error propagation.
2026-06-06fix(array-merge): route mixed-key merges through faithful array_mergensfisis
* Config::merge called array_merge_recursive where PHP uses plain array_merge (string-key overwrite); switch those six sites to array_merge. * provides/replaces merges that may carry an AliasPackage's self.version numeric keys ("0","1",...) were collapsing under naive chain/insert/or_insert; route them through a new array_merge_map(). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06fix(dependency-resolver): preserve PHP array keying for alias linksnsfisis
Mirror PHP's array_merge semantics in AliasPackage so self.version provide/replace/conflict links are appended under numeric keys ("0", "1", ...) instead of collapsing onto the target-name key. This keeps both the original and alias-version links and makes Pool::match's contains_key("0") check (= PHP isset($x[0])) work as intended. replace_self_version_dependencies now takes and returns IndexMap<String, Link>, dropping the lossy re-key-by-target in the AliasPackage/RootAliasPackage constructors. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06feat(dependency-resolver): delegate get_operations to inner transactionnsfisis
Resolve TODO(phase-b) in LocalRepoTransaction. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06feat(console): pass styles through HtmlOutputFormatter constructornsfisis
Resolve TODO(phase-b): mirror PHP's parent::__construct(true, $styles) by extending the base OutputFormatter::new to accept a style map. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06fix(command): use full pretty version and drop stale phase-b TODOsnsfisis
LicensesCommand now renders the root package version via get_full_pretty_version, matching PHP getFullPrettyVersion, and holds the root package handle directly instead of snapshotting fields. Also align update/mark-alias operations on get_full_pretty_version and remove the now-stale phase-b TODO markers in status and licenses commands. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06feat(command): merge local and remote repos in browse commandnsfisis
initialize_repos now appends the local repository and remote repositories from the repository manager after the root package repo, matching PHP HomeCommand::initializeRepos. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06feat(command): wire exec binary as __exec_command listenernsfisis
Register the selected binary as a Callable::String listener for the __exec_command event, matching PHP ExecCommand's addListener call. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06refactor(repository): make read methods fallible and take &mut selfnsfisis
Change RepositoryInterface and WritableRepositoryInterface read methods (find_package, find_packages, get_packages, load_packages, search, get_providers, get_canonical_packages) to take &mut self and return anyhow::Result, so lazy-loading repositories such as ComposerRepository can perform fallible I/O and mutate internal state on access. Update all implementors and call sites to propagate the Result and pass mutable references. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05feat(command): wire do_execute for depends/prohibits commandsnsfisis
Forward execute() to BaseDependencyCommand::do_execute, mirroring the PHP commands that delegate to parent::doExecute (inverted=true for prohibits). Add the missing BaseDependencyCommand impl on DependsCommand. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05refactor(autoload): drop deprecated Autoload\ClassMapGenerator implnsfisis
Composer\Autoload\ClassMapGenerator has been deprecated since Composer 2.4.0 and is no longer referenced by Composer itself, which uses the composer/class-map-generator package directly. Remove its dump/createMap port (and the unwired scanned_files TODO), keeping only the type with a #[deprecated] attribute and a TODO(plugin) note so it can be implemented later for plugins that may still rely on it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05feat(advisory): parse sources into typed full advisorynsfisis
Replace the todo!() placeholder in PartialSecurityAdvisory::create with a real conversion of the PhpMixed sources list into Vec<IndexMap<String, String>>, so the full advisory path no longer panics. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05refactor(json): make json encode helpers accept serde::Serializensfisis
Change json_encode/json_encode_ex and JsonFile::encode/encode_with_options to take a generic serde::Serialize value instead of &PhpMixed, implement Serialize for PhpMixed/ArrayObject, and drop the PhpMixed::String wrapping at JsonManipulator call sites in favor of passing raw values. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05refactor(json): model JsonFile encode/write options as a typed structnsfisis
Replace the i64 bitmask + encode_with_indent split with a JsonEncodeOptions struct (Default = JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE, default indent). encode/write each get a default form plus an explicit encode_with_options/write_with_options variant, mirroring PHP's optional $options argument. write_with_options always encodes with self.indent, matching PHP write(). Also reconcile call sites with the PHP sources: most ported sites passed 0 where Composer omits the argument (= default flags), so JsonManipulator/ShowCommand and JsonConfigSource now use the default options; only ComposerRepository and Locker genuinely pass 0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05feat(json-lint): port ParsingException details into a typed structnsfisis
Replace the Phase B stub that discarded ParsingException details with a dedicated ParsingExceptionDetails struct (text/token/line/loc/expected), modeling the PHP string|int token union as a ParsingExceptionToken enum. Wire JsonFile::validate_syntax to forward the source details and let Application read the error line from the typed accessor. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05feat(dependency-resolver): share operations via Rc, drop clone_boxnsfisis
OperationInterface::clone_box (a todo!() trait-object clone stub) is removed in favor of Rc<dyn OperationInterface> shared ownership. All its methods are &self, so operations are immutable value objects that Rc can share; pushing the same operation into multiple lists (installer's install/uninstall splits) becomes a cheap Rc clone instead of clone_box. Box<dyn OperationInterface> is replaced with Rc<dyn ...> across Transaction (and its Lock/LocalRepo wrappers), Installer, PackageEvent, InstallationManager and EventDispatcher; Box::new operation constructions become Rc::new. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05feat(filter): share platform req filter via Rc, drop clone_boxnsfisis
PlatformRequirementFilterInterface::clone_box (a todo!() trait-object clone stub) is removed in favor of Rc<dyn ...> shared ownership, matching PHP's by-reference sharing of the single filter object. Box<dyn ...> is replaced with Rc<dyn ...> across the factory, Solver/RuleSetGenerator, VersionSelector, AutoloadGenerator, Installer and the command layer (BaseCommand/PackageDiscoveryTrait and their impls); clone_box call sites become Rc clones. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05feat(dependency-resolver): share policy via Rc, drop clone_boxnsfisis
PolicyInterface::clone_box (a todo!() trait-object clone stub) is removed in favor of Rc<dyn PolicyInterface> shared ownership, matching PHP's by-reference sharing of the single $policy object across Solver, RuleSetGenerator and PoolOptimizer. With PoolOptimizer::new now taking an Rc, Installer::create_pool_optimizer is implemented faithfully (return new PoolOptimizer($policy)); create_policy returns the shared Rc. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05feat(installer): wire InstallerInterface marker-trait downcastsnsfisis
Add as_binary_presence_interface and as_plugin_installer_mut to InstallerInterface following the downloader marker-trait downcast pattern, so InstallationManager can model the PHP instanceof checks in ensureBinariesPresence and disablePlugins. Make BinaryPresenceInterface take &mut self, resolving LibraryInstaller's stubbed trait impl. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05refactor(downloader): return Result from GitDownloader::view_diffnsfisis
PHP's viewDiff returns void but throws RuntimeException when git diff fails. Model it as Result<()> and propagate via ? at the single caller instead of panicking. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05refactor(io): model ask_and_validate validators with anyhow::Resultnsfisis
PHP's askAndValidate throws when a validator rejects input. Change the IOInterface validator callback and return type to anyhow::Result so the call sites can return Err instead of panic, faithfully modeling the throw semantics already supported by the Question layer. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05feat(downloader): wire ArchiveDownloader extraction and Path/Zip overridesnsfisis
Implement ArchiveDownloader for Zip/Tar/Gzip/Xz/Phar/Rar so install() extracts the archive (extract + rename) instead of doing FileDownloader's plain file rename, and route install/prepare/cleanup through the mixin. ArchiveDownloader::extract becomes &mut self to match the concrete implementations. Route ZipDownloader's bespoke download() (unzip-command static init) and PathDownloader's symlink/junction/mirror download/install/remove through the DownloaderInterface trait (path: String -> &str). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05feat(downloader): wire VcsDownloader subclasses via shared downloadersnsfisis
Share downloaders as Rc<RefCell<dyn DownloaderInterface>> in DownloadManager and make DownloaderInterface/VcsDownloader take &mut self, matching PHP's mutable-by-reference downloader objects. This lets Git/Svn/Hg/Fossil/Perforce implement VcsDownloader and route download/install/update/prepare/cleanup through the trait instead of todo!(), and wires the as_* downcast hooks end-to-end. ChangeReportInterface::get_local_changes becomes &mut self since FileDownloader downloads to a compare dir; get_commit_logs/reapply_changes gain &mut self / Result to match the concrete implementations. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04feat(loader): wire RootPackageLoader::load end-to-endnsfisis
Resolve the remaining todo!()/placeholder sites in RootPackageLoader::load so the root package loads with real data: - Unbox config at use sites and change load()'s parameter from IndexMap<String, Box<PhpMixed>> to IndexMap<String, PhpMixed>, matching ArrayLoader::load / VersionGuesser::guess_version and dropping the redundant box/unbox round-trip at the factory call site. - Expose replace_version through CompletePackage/RootPackage inherent delegation and a RootPackageHandle method (PHP Package::replaceVersion, inherited), and apply it for the auto-versioned default. - Collect require/require-dev links via getter dispatch and build the pretty-string map feeding extractAliases/StabilityFlags/References. Also reconcile the package repositories type with Config: change CompletePackageInterface::{get,set}_repositories from Vec<IndexMap<String, PhpMixed>> to IndexMap<String, PhpMixed> (PHP's array<int|string, mixed>), wire setRepositories(config.getRepositories()), and dump repositories verbatim as a keyed array (matching PHP ArrayDumper) instead of forcing a list. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04feat(locker): wire get_locked_repository via LockArrayRepositorynsfisis
Implement LockArrayRepository::new/add_package and CanonicalPackagesTrait::get_packages (delegating to inner ArrayRepository), expose add_package on LockArrayRepositoryHandle, and add set_root_package_alias on CompleteAliasPackageHandle. With these in place, Locker::get_locked_repository is fully wired: load each locked package, register it (plus its aliasOf for AliasPackages) in package_by_name, then build CompleteAliasPackage handles for lock-file aliases via as_complete_package() narrowing. Drop the unused RepositoryInterface::clone_box default and the stale inherent LockArrayRepository::clone_box (no callers). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04feat(loader): wire ArrayLoader::load end-to-end ↵nsfisis
(create_object/configure_object/dispatch) Make ArrayLoader::load build and return a fully configured package for both the CompletePackage and RootPackage class strings. - Introduce a private CompleteOrRootPackage enum to model PHP's createObject(): CompletePackage return (RootPackage extends CompletePackage), with accessors for the inner Package, the CompletePackageInterface view, and conversion into a PackageInterfaceHandle. - create_object: instantiate CompletePackage/RootPackage by class string. - load / configure_cached_links: implement the dynamic setter dispatch ($package->{'set'.ucfirst($method)}($links)) via apply_link_setter. - configure_object: wire all ~21 setters (Package inherent + CompletePackageInterface), source/dist with Mirror conversion, suggest self.version replacement, release date, and the branch-alias return (RootAliasPackage/CompleteAliasPackage). The PHP `instanceof CompletePackage` guard in configureObject is dropped: it is unreachable since createObject is private and returns `: CompletePackage`, an invariant now enforced at compile time by the enum. DateTime parsing for `time` keeps its existing approximate scaffold (noted with a TODO). RootPackage.inner is made pub(crate) (matching CompletePackage.inner) so the loader can reach the core Package. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04feat(package): implement PackageInterface accessor layer for ↵nsfisis
Package/CompletePackage/RootPackage Fill the trait-impl todo!() across the package accessor layer so loaded packages are actually usable (the ArrayLoader::load path depends on it): - Package: implement BasePackage/PackageInterface from struct fields and existing inherent methods; Display via get_unique_name. - CompletePackage: delegate PackageInterface to inner Package. - RootPackage: delegate CompletePackageInterface/PackageInterface to inner CompletePackage; RootPackageInterface link setters delegate to Package. Correct three unfaithful trait signatures found during implementation: - get_target_dir returns Option<String> (PHP computes a normalized value; a borrow cannot represent it, and AliasPackage could not implement &str across its aliasOf handle). - RootPackageInterface link setters take IndexMap<String, Link>, matching Package and the real ArrayLoader caller (PHP RootPackage inherits Package::setRequires; the Link[] docblock was imprecise). - get_full_pretty_version takes a DisplayMode enum instead of a raw i64; the match is now exhaustive, so it returns String without an error path. Move mirror conversion to the boundaries: PackageInterface mirror methods use Vec<Mirror> (the typed form, matching the inherent methods), with array<->Mirror conversion done by the producer (ComposerRepository) and consumer (ArrayDumper). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04feat: resolve trivial todo!() sites with existing constructorsnsfisis
Replace todo!("VersionParser::new()") with VersionParser::new() at 6 call sites (array_loader, base_command, create_project_command, vcs_repository, http_downloader x2) and EventDispatcher::io_clone with self.io.clone(). All targets already exist on their types. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04refactor: drop stale phase-b TODO comments resolved by current codensfisis
These TODOs describe work already done: writeError per-line iteration (github, remote_filesystem, svn_downloader) and reference equality via std::ptr::eq (download_manager). No behavior change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03feat(downloader): return Result from getUnpushedChanges to bubble ↵nsfisis
RuntimeException Match PHP GitDownloader::getUnpushedChanges, which returns ?string while throwing \RuntimeException on git command failure. Change the signature to Result<Option<String>> and replace the three panic\!() sites with Err(RuntimeException), mirroring the get_local_changes port. Thread ? through the clean_changes and StatusCommand call sites. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03feat(downloader): implement ChangeReport/VcsCapable for VCS downloadersnsfisis
Git/Svn/Hg/Fossil/Perforce now implement ChangeReportInterface and VcsCapableDownloaderInterface and override the as_* downcasts, so PHP-style instanceof checks on a DownloaderInterface resolve to these sub-interfaces. get_local_changes lives directly in the ChangeReportInterface impl (returning anyhow::Result; GitDownloader now surfaces a RuntimeException instead of panicking on a failed git status). get_vcs_reference is shared via a new VcsDownloaderBase helper that each downloader delegates to. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03feat(downloader): wire as_* downcasts for file/archive/path/git downloadersnsfisis
Override DownloaderInterface's as_change_report_interface / as_vcs_capable_downloader_interface / as_dvcs_downloader_interface so PHP-style instanceof checks resolve to the concrete sub-interface: FileDownloader and the six archive downloaders (Zip/Tar/Gzip/Xz/Rar/Phar) plus PathDownloader gain ChangeReportInterface (archives/path delegate to the inner FileDownloader), PathDownloader exposes VcsCapableDownloaderInterface, and GitDownloader exposes DvcsDownloaderInterface. The default None impls remain correct for downloaders that do not implement a given sub-interface, so their stale TODO markers are dropped. VCS downloaders' ChangeReport/VcsCapable conformance follows separately. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03fix(config,loader): wire JsonValidationException catch; drop unportable ↵nsfisis
chain TODOs JsonConfigSource::manipulate_json now downcasts the validate_schema error to JsonValidationException (matching PHP's specific catch), restores the original contents, and surfaces e.get_errors(); other errors propagate. ArrayLoader's two version-parse catch sites only had TODOs for preserving the original exception as 'previous'. shirabe_semver raises generic anyhow errors (not shim exception types), so the existing catch-all is already faithful to PHP's catch (\UnexpectedValueException), and the flat shim exception structs intentionally hold no previous field; the wrapped message already carries the original cause. Remove the stale TODOs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>