resolve() returns no error for a package the pool could not supply #10

Open
opened 2026-09-28 07:09:52 -03:00 by marcos-mendez · 0 comments
marcos-mendez commented 2026-09-28 07:09:52 -03:00 (Migrated from github.com)

Found while inventorying the call sites for #8. Not introduced by #9, and not
a blocker for it; filed because it is the thing that turns a missing package
into a silently wrong image rather than a build failure.

resolve() cannot report a missing package

fablib/plan.py:

  • missing is initialised at :366 and never mutated afterwards.
  • brokendeps is built by iterating missing at :421-422.
  • So resolve() returns (spec, []) even when all_missing is non-empty.

A plan entry the pool cannot supply is dropped from the spec and the caller is
told nothing. fab-plan-resolve exits 0 and the build carries on without the
package.

And a virtual package can never resolve

Two things, both at the same layer:

  • :205-206 derives the package name from the pool's answer with
    package_name = fname.split("_")[0] and then indexes deps[package_name].
    The first field of the .deb filename has to be string-equal to the name
    that was requested, so a provider returned under a different name raises an
    uncaught KeyError rather than resolving.
  • _get_provided at :329 reads Provides only from packages that have
    already been fetched, and its result is used only at :406 to subtract from
    all_missing. Nothing in that path can cause a provider to be fetched in the
    first place.

So Provides: is not a mechanism a plan can rely on, and the first defect
means that when it fails, it fails quietly.

Why it matters now

tkldev/plan/main:3 is a bare fab, the only plan in the organization that
names the package. After #9 the package is keel-fab, and Provides: fab
does not help a plan. That is Keel-Linux/tkldev#4, which fixes the plan line;
this issue is about the resolver telling the truth when a plan line is wrong.

What closes this

  • resolve() reports what it could not supply, with a test that drives it
    against a pool missing a requested package and asserts a non-zero result
    rather than an empty brokendeps.
  • A decision on virtual packages: either resolve them properly, or refuse a
    plan entry that only matches a Provides with a message saying so. Refusing
    loudly is worth more than resolving quietly here.
  • Whichever is chosen, the KeyError path at :205-206 becomes a diagnosed
    error rather than a traceback.

Coverage: fablib/plan.py is 314 lines and currently has no unit test at all
(COVERAGE.md, priority 2 of the plan to reach 90 percent). This is a good
reason to start there.

Found while inventorying the call sites for #8. Not introduced by #9, and not a blocker for it; filed because it is the thing that turns a missing package into a silently wrong image rather than a build failure. ## `resolve()` cannot report a missing package `fablib/plan.py`: - `missing` is initialised at `:366` and **never mutated** afterwards. - `brokendeps` is built by iterating `missing` at `:421-422`. - So `resolve()` returns `(spec, [])` even when `all_missing` is non-empty. A plan entry the pool cannot supply is dropped from the spec and the caller is told nothing. `fab-plan-resolve` exits 0 and the build carries on without the package. ## And a virtual package can never resolve Two things, both at the same layer: - `:205-206` derives the package name from the pool's answer with `package_name = fname.split("_")[0]` and then indexes `deps[package_name]`. The first field of the `.deb` filename has to be string-equal to the name that was requested, so a provider returned under a different name raises an uncaught `KeyError` rather than resolving. - `_get_provided` at `:329` reads `Provides` only from packages that have already been fetched, and its result is used only at `:406` to subtract from `all_missing`. Nothing in that path can cause a provider to be fetched in the first place. So `Provides:` is not a mechanism a plan can rely on, and the first defect means that when it fails, it fails quietly. ## Why it matters now `tkldev/plan/main:3` is a bare `fab`, the only plan in the organization that names the package. After #9 the package is `keel-fab`, and `Provides: fab` does not help a plan. That is Keel-Linux/tkldev#4, which fixes the plan line; this issue is about the resolver telling the truth when a plan line is wrong. ## What closes this - `resolve()` reports what it could not supply, with a test that drives it against a pool missing a requested package and asserts a non-zero result rather than an empty `brokendeps`. - A decision on virtual packages: either resolve them properly, or refuse a plan entry that only matches a `Provides` with a message saying so. Refusing loudly is worth more than resolving quietly here. - Whichever is chosen, the `KeyError` path at `:205-206` becomes a diagnosed error rather than a traceback. Coverage: `fablib/plan.py` is 314 lines and currently has no unit test at all (`COVERAGE.md`, priority 2 of the plan to reach 90 percent). This is a good reason to start there.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Keel-Linux/fab#10
No description provided.