Hello to everyone.
I realized that when I do a "pkg upgrade",some installed packages silent drops : it means that they are removed without notice. For this reason,I asked Claude to elaborate a strategy for making a better upgrading / installing packages strategy.
Since I do "vibe coding",no one will be interested to the code I produce,so I will not be involved personally in this project. Anyway,I want to propose the plan to someone that can code it personally,using his brain :
So,this is what Claude (Opus 5.5) suggested :
1. It's not exactly "silent", but the policy is wrong.
pkg upgrade does show an Installed packages to be REMOVED section and asks for confirmation, unless -y or ASSUME_ALWAYS_YES is set. In a 200-line plan, though, that section is easy to miss. The real flaw is elsewhere: pkg's SAT solver (picosat) treats removal as an operation just as legitimate as an upgrade. There is no --never-remove-style option that turns a removal into an error.
2. The ecosystem limit.
FreeBSD repositories (quarterly/latest) carry only one version per origin. If py39-foo disappears from the repo or conflicts with the new py311 default, no solver can "find the best combination" using the repo alone, because that combination doesn't exist. The only way to give the solver a choice is to make additional versions available to it. So this is not just a better solver: it also needs a richer catalog.
A. Snapshot of the initial state.
For every installed package, record: origin, flavor, version, automatic flag, lock state, shlibs_provided and shlibs_required (via pkg query). Before touching anything, create a ZFS boot environment with bectl create.
B. Multi-source catalog with priorities.
C. Problem model (MaxSAT / pseudo-boolean, CUDF/Mancoosi style).
Hard constraints:
D. Lexicographic objective, in strict order: a lower level can never compensate for a worse result at a higher one.
It extracts the minimal unsatisfiable subset (MUS) and reports it in readable form, for example: "X cannot stay because it requires libfoo.so.3, provided only by Y, which conflicts with Z, required by W". It then lists the concrete alternatives: keep W at the old version, remove X, or build X in poudriere. The decision stays with the user and is never made implicitly.
F. Execution.
The plan is translated into explicit operations on specific .pkg files, not into a generic pkg upgrade that would recompute everything from scratch. Packages kept at an old version get pkg lock, so the next bare pkg upgrade doesn't throw them away.
G. Final verification.
Diff the initial snapshot against the final one and check shlibs with pkg check -d and pkg check -B. If something doesn't add up, roll back to the boot environment.
I realized that when I do a "pkg upgrade",some installed packages silent drops : it means that they are removed without notice. For this reason,I asked Claude to elaborate a strategy for making a better upgrading / installing packages strategy.
Since I do "vibe coding",no one will be interested to the code I produce,so I will not be involved personally in this project. Anyway,I want to propose the plan to someone that can code it personally,using his brain :
So,this is what Claude (Opus 5.5) suggested :
1. It's not exactly "silent", but the policy is wrong.
pkg upgrade does show an Installed packages to be REMOVED section and asks for confirmation, unless -y or ASSUME_ALWAYS_YES is set. In a 200-line plan, though, that section is easy to miss. The real flaw is elsewhere: pkg's SAT solver (picosat) treats removal as an operation just as legitimate as an upgrade. There is no --never-remove-style option that turns a removal into an error.
2. The ecosystem limit.
FreeBSD repositories (quarterly/latest) carry only one version per origin. If py39-foo disappears from the repo or conflicts with the new py311 default, no solver can "find the best combination" using the repo alone, because that combination doesn't exist. The only way to give the solver a choice is to make additional versions available to it. So this is not just a better solver: it also needs a richer catalog.
Design
A. Snapshot of the initial state.
For every installed package, record: origin, flavor, version, automatic flag, lock state, shlibs_provided and shlibs_required (via pkg query). Before touching anything, create a ZFS boot environment with bectl create.
B. Multi-source catalog with priorities.
- Remote repo (quarterly or latest).
- A local repo generated with pkg repo over /var/cache/pkg. It contains the currently installed packages, so "keep the old version" is always an available choice.
- Optional: a personal poudriere repo, for ports removed from the official tree.
C. Problem model (MaxSAT / pseudo-boolean, CUDF/Mancoosi style).
Hard constraints:
- dependencies (origin/flavor);
- declared conflicts and file conflicts;
- at most one version per origin;
- every shlib_required of the selected packages must be provided by a selected package or by the base system.
D. Lexicographic objective, in strict order: a lower level can never compensate for a worse result at a higher one.
- Zero removals of explicitly installed (non-automatic) packages.
- Minimum number of removals of dependencies that are still required.
- Minimum number of packages kept at an old version or downgraded.
- Maximum number of packages brought to the newest version.
- Minimum number of newly installed packages.
It extracts the minimal unsatisfiable subset (MUS) and reports it in readable form, for example: "X cannot stay because it requires libfoo.so.3, provided only by Y, which conflicts with Z, required by W". It then lists the concrete alternatives: keep W at the old version, remove X, or build X in poudriere. The decision stays with the user and is never made implicitly.
F. Execution.
The plan is translated into explicit operations on specific .pkg files, not into a generic pkg upgrade that would recompute everything from scratch. Packages kept at an old version get pkg lock, so the next bare pkg upgrade doesn't throw them away.
G. Final verification.
Diff the initial snapshot against the final one and check shlibs with pkg check -d and pkg check -B. If something doesn't add up, roll back to the boot environment.
Implementation
- libsolv (BSD-3 license, the solver used by zypper and dnf). It already has the concepts of installed packages to preserve, "lock" and "favor" jobs, and problem explanations with alternative solutions. The main work is converting the pkg catalog (packagesite.yaml, one JSON object per line, with shlibs as "provides") into libsolv's format.
- Alternative: direct MaxSAT with PySAT/RC2 (MIT). More control over the lexicographic objective, but MUS extraction and the explanations have to be written from scratch.