2 Commits
Author SHA1 Message Date
Oleksandr ShyshatskyiandClaude Opus 5 09e1e6521f patch.sh was asking the payload questions its recipes had already answered
Four sections went. Three of them were checks: _sqlite3 by name, which
pkgs/3rdparty/python/build.sh already made; libsodium's symlink, which
pkgs/3rdparty/libsodium/build.sh already made; and an ABI walk of the whole
payload, which bin/build-packages.sh makes over every PKG_ROOT on the way into
every .ipk -- from the packaging loop rather than a build.sh, so cached trees
are re-read too.

The fourth was not a check. config.env's BUSYBOX_BIN was copied into the
payload here, which made it the one file no package owned: an allowance in the
"every file is owned" test, an ABI gate of its own because the payload-wide one
ran before the copy, and a file no `opkg remove` could take away. It is
pkgs/3rdparty/busybox now, PKG_WHEN-gated on BUSYBOX_BIN, and it needed a third
source verb -- pkg_prebuilt, beside pkg_unpack and pkg_intree -- because a
recipe names its source exactly once and this one's source is a path someone
typed. Once it was a package, nothing in the payload came from outside the
feed, which is what made the payload-wide ABI gate redundant rather than merely
duplicated.

The "at least twelve extension modules in site-packages" count was the one
check with nowhere to go and no duplicate. It is pkg_pynative in the seven
python-* recipes that ship a .so: an aggregate could say that a native package
had fallen back to a pure-python wheel but never which one, and each of those
recipes can say it about itself.

What that costs is written into the section it left: a gate inside build.sh
does not run on a cache hit, and no python recipe sets PKG_STAMP_EXTRA. That is
pkg_stamp's problem, not an argument for a second copy of every check here.

Measured: `make packages` builds anvil-busybox_1.31.1-1_mipsel_xburst2.ipk,
`make build` assembles a 32-package payload whose bin/busybox is listed in
anvil-busybox.list, and qa-static is 265 passed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011gKRUCqj18TVF1Vz1oMpmC
2026-08-29 15:24:20 +03:00
Oleksandr ShyshatskyiandClaude Opus 5 f67e7a269f ls pkg/ was thirty-eight entries and four of them mattered
pkg/ -> pkgs/, and the thirty-four recipes that build a pinned tarball and
carry no files of this repo move down a level into pkgs/3rdparty/. What is
left at the top is the four components a person actually edits: anvil-core,
klipper, moonraker, helixscreen.

THE LINE IS MECHANICAL, NOT EDITORIAL, and that is why it can be a directory
rather than a field in pkg.conf. "Do we actively modify it" drifts -- the day
somebody patches zlib nobody would agree which side it belongs on, and the
answer would be a rename touching CI and docs decided by taste. "Does it carry
files of ours" is a fact about the tree: it is exactly whether the recipe has
a payload/, prog/ or seed/, checkable in one assertion, and
test_recipe_layout.py now demands the move in both directions -- a 3rdparty
recipe that grows one of the three must come up, and a top-level recipe with
none of them must go down, or the top level slowly refills and the split stops
meaning anything.

ONE FUNCTION KNOWS THE TWO DEPTHS. pkgs/lib.sh's pkg_dir resolves a recipe id
to its directory and nothing else spells either path -- not a recipe, not
bin/build-packages.sh, not a test. Names stay unique across both levels
because pkg_out, pkg_stamp and the .ipk filename are all keyed by the bare
name; a duplicate would resolve to whichever level is searched first and
build the wrong thing silently, so that is a test too.

Recipes now source `. ./bin/common.sh` instead of counting `..` from $0.
Depth-counting would have needed two spellings for two levels, and it was
never buying anything: `. pkg/lib.sh` on the next line already required the
working directory to be the repo root.

A SECOND SILENT-SHRINK BUG, and this one was live. qa/static's _files()
expanded a list of globs and returned whatever matched, so "pkgs/*/build.sh"
quietly stopped covering thirty-four recipes the moment they moved -- the lane
stayed green, and the only visible sign was a test count dropping by 34 in a
run nobody was counting. _files() now refuses a pattern that matches nothing.
That is the same failure the ash-compatibility check had a guard for and the
syntax check did not, which is why the guard reads the way it does.

AND ONE PACKAGE WAS SHIPPING PYTHON BYTECODE. anvil-core stages a directory of
.py helpers wholesale, so any test that imported one left a __pycache__ beside
it -- gitignored, invisible in a diff, copied by cp -a like anything else. The
package's contents depended on whether pytest had been run on the machine that
built it: two builds of one commit, different sha256, cause nowhere in the
tree. What it shipped was worthless as well as unstable, compiled by the build
image's python 3.11 for a printer running the 3.13 this repo cross-builds. The
sweep is in pkg_ship now, once, and the two hand-written copies in
pkgs/klipper and pkgs/moonraker are deleted -- the trap is set for any recipe
that stages a tree of .py files, and the two recipes that had hit it had each
solved it locally while the third, which had not, was the one shipping.

Measured:
  * the rename changes no package bytes. Same cached build trees, feed built
    with the diff stashed and unstashed: all 41 .ipk match.
  * with the bytecode sweep, anvil-core returns to exactly the bytes the
    previous commit produced.
  * no package in the feed contains a .pyc or a __pycache__.
  * make qa-static: 247 passed (236 before this work + 11 layout tests).
  * make test: 8 passed, 0 failed, including unpack/patch/pack/verify on the
    synthetic stock package. make test-py: 181 passed.

Not explained: anvil-python-dev produced two different sha256 from an
UNCHANGED work/pkg/python at two points today, under code that was identical
both times -- so it is not reproducible from a cached tree, and it is not this
commit's doing (the stashed and unstashed builds above agree on it). Worth a
look; the dev split in bin/build-packages.sh is where to start.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 20:04:20 +03:00