Which of a site's drupal/* packages need a new release for a target core, and which have none? Send composer.lock and composer.json once; do not query one package at a time. The answer is the release scan for every package, plus extra.patches as check_patches items. Constraints are read by composer's own semver library.
- composer_lock: the whole file, or its path to get the upload command. A real lock does not fit a call. With the path, the files go from disk to the api by curl and only the plan comes back. composer_json: adds constraints and extra.patches. patches_file and patches_lock: the two documents a site on cweagans/composer-patches 2.x keeps its patches in, since such a site declares none under extra.patches. Sent as text with a lock path, the command lists every patch to send. target_core: 11.4, 11.4.5, or latest for the newest core the site's constraint allows. Without patches, target_from holds the package whose constraint decided latest. When the site requires no core package, latest is the installed core and target_from says so. Empty scans against the installed core (target_is_installed): what can be updated without a core upgrade.
- installed_unknown: the release data does not have the installed version; the row offers no older release. installed_from_tag: the project's git tag answered instead. Neither is a finding about the site.
- A sub-module has no releases of its own; drupal.org packages it as a metapackage built from its project's release. Its row says submodule_of and has that project's answer. The lock's type, require and extra.drupal.datestamp fields pair a metapackage with its project.
- rows, problems first. no_release: no published release supports the target; latest_any and dev_branch say what exists. update: a compatible release the site does not have; latest, latest_core. unknown: not a drupal.org project in the bundle; note says where its releases are. current: installed_supports and nothing newer needed; such a row has package, installed and installed_supports only. counts covers every package even when rows are cut.
- candidates, on every row that is not current: the newest three releases, each with version, core constraint, date and supports_target. project_profile adds installs and branches to the same three.
- patches: one item per declared patch with the installed version filled in. Pass them to check_patches after composer update; local paths need the file text. A patch on a package outside drupal/ gets no item and no row; outside_drupal lists it.
- patches:true answers with plan instead: every patch judged against the release its package would install for target_core. plan.counts: the verdict tally. plan.package_counts: the scan tallies. plan.no_release: the packages that block the target. plan.patches: one row per patch needing a decision (conflicts, unknown, merged, and an applies that only a lenient apply took). plan.applying: the number that apply with nothing to decide. The scan rows are not in a plan; call again without patches for them.
- A patch whose package has no release for the target is judged against the branch when the lock installs a dev version. Otherwise it is unknown, with the reason in note. plan.warnings: a package is in no_release because of something the site controls. Each warning gives the requirement to change: its own constraint, or its minimum stability. A row's project for reroll_patch is its package without the drupal/ prefix.
- A plan never has a re-rolled diff. plan.next_step points at reroll_patch, one call per patch, when any patch needs a re-roll.
- bundle_date: when the release data was published. A release after it is invisible here. Confirm a no_release with composer show or drupal.org before acting.